public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 02/34] [Ada catchpoints] Fix "warning: failed to get exception name: No definition of \"e.full_name\" in current context"
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

Looking at testsuite results, I noticed this warning in an MI test:

 ~"\nCatchpoint "
 ~"2, "
 &"warning: failed to get exception name: No definition of \"e.full_name\" in current context.\n"
 ~"exception at 0x000000000040192d in foo () at /home/pedro/brno/pedro/gdb/mygit/src/gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb:20\n"
 ~"20\t      raise Constraint_Error;  -- SPOT1\n"
 *stopped,reason="breakpoint-hit",disp="keep",bkptno="2",exception-name="CONSTRAINT_ERROR",frame={addr="0x000000000040192d",func="foo",args=[],file="/home/pedro/brno/pedro/gdb/mygit/src/gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb",fullname="/home/pedro/brno/pedro/gdb/mygit/src/gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb",line="20"},thread-id="1",stopped-threads="all",core="5"
 (gdb)
 PASS: gdb.ada/mi_catch_ex.exp: continue until CE caught by all-exceptions catchpoint

The problem is that:

  - MI prints the breakpoint hit twice: once on the MI stream;
    another time on the console stream.

  - After printing the Ada catchpoint hit, gdb selects a non-current
    frame, from within the catchpoint's print_it routine.

So the second time the breakpoint is printed, the selected frame is no
longer the current frame, and then evaluating e.full_name in
ada_exception_name_addr fails.

This commit fixes the problem and enhances the gdb.ada/mi_catch_ex.exp
test to make sure the catchpoint hit is printed correctly on the
console stream too.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* ada-lang.c (ada_exception_name_addr_1): Add comment.
	(print_it_exception): Select the current frame.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.ada/mi_catch_ex.exp (continue_to_exception): New procedure.
	(top level): Use it instead of mi_execute_to.
---
 gdb/ada-lang.c                        |  9 ++++++++
 gdb/testsuite/gdb.ada/mi_catch_ex.exp | 41 ++++++++++++++++++++++++++---------
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 412aa97..3c5ab26 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -12183,6 +12183,8 @@ ada_unhandled_exception_name_addr_from_raise (void)
    (of any type), return the address in inferior memory where the name
    of the exception is stored, if applicable.
 
+   Assumes the selected frame is the current frame.
+
    Return zero if the address could not be computed, or if not relevant.  */
 
 static CORE_ADDR
@@ -12484,6 +12486,13 @@ print_it_exception (enum ada_exception_catchpoint_kind ex, bpstat bs)
   ui_out_field_int (uiout, "bkptno", b->number);
   ui_out_text (uiout, ", ");
 
+  /* ada_exception_name_addr relies on the selected frame being the
+     current frame.  Need to do this here because this function may be
+     called more than once when printing a stop, and below, we'll
+     select the first frame past the Ada run-time (see
+     ada_find_printable_frame).  */
+  select_frame (get_current_frame ());
+
   switch (ex)
     {
       case ada_catch_exception:
diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex.exp b/gdb/testsuite/gdb.ada/mi_catch_ex.exp
index 320f3bf..288a065 100644
--- a/gdb/testsuite/gdb.ada/mi_catch_ex.exp
+++ b/gdb/testsuite/gdb.ada/mi_catch_ex.exp
@@ -78,17 +78,38 @@ mi_gdb_test "-catch-exception" \
             "\\^done,bkptno=\"$decimal\",bkpt={.*disp=\"keep\",enabled=\"y\",addr=\"$hex\",what=\"all Ada exceptions\",.*}" \
             "catch all exceptions"
 
-mi_execute_to "exec-continue" \
-              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"CONSTRAINT_ERROR" \
-              "foo" "" ".*" ".*" \
-              ".*" \
-              "continue until CE caught by all-exceptions catchpoint"
+# Continue to caught exception.
 
-mi_execute_to "exec-continue" \
-              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"PROGRAM_ERROR" \
-              "foo" "" ".*" ".*" \
-              ".*" \
-              "continue until PE caught by all-exceptions catchpoint"
+proc continue_to_exception { exception_name test } {
+    global hex any_nb
+
+    mi_send_resuming_command "exec-continue" "$test"
+
+    # Match console stream output.
+    gdb_expect {
+	-re " $exception_name at $hex in foo " {
+	}
+	timeout {
+	    fail "$test (timeout)"
+	    return -1
+	}
+    }
+
+    # Now MI stream output.
+    mi_expect_stop \
+	"breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"$exception_name" \
+	"foo" "" ".*" ".*" \
+	".*" \
+	$test
+}
+
+continue_to_exception \
+    "CONSTRAINT_ERROR" \
+    "continue until CE caught by all-exceptions catchpoint"
+
+continue_to_exception \
+    "PROGRAM_ERROR" \
+    "continue until PE caught by all-exceptions catchpoint"
 
 ################################################
 # 2. Try catching only some of the exceptions. #
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 14/34] Make command line editing (use of readline) be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (5 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 33/34] Make mi-break.exp always expect breakpoint commands output on the main UI Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 15/34] Always process target events in the main UI Pedro Alves
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

Due to the way that readline's API works (based on globals), we can
only have one instance of readline in a process.  So the goal of this
patch is to only allow editing in the main UI, and make sure that only
one UI calls into readline.  Some MI paths touch readline variables
currently, which is bad as that is changing variables that matter for
the main console UI.  This patch fixes those.

This actually fixes a nasty bug -- starting gdb in MI mode ("gdb
-i=mi"), and then doing "set editing on" crashes GDB, because MI is
not prepared to use readline:

 set editing on
 &"set editing on\n"
 =cmd-param-changed,param="editing",value="on"
 ^done
 (gdb)
 p 1
 readline: readline_callback_read_char() called with no handler!
 Aborted (core dumped)

The fix for that was to add an interp_proc method to query the
interpreter whether it actually supports editing.  New test included.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	PR mi/20034
	* cli/cli-interp.c: Include cli-interp.h and event-top.h.
	(cli_interpreter_resume): Pass 1 to gdb_setup_readline.  Set the
	UI's input_handler here.
	(cli_interpreter_supports_command_editing): New function.
	(cli_interp_procs): Install it.
	* cli/cli-interp.h: New file.
	* event-top.c (async_command_editing_p): Rename to ...
	(set_editing_cmd_var): ... this.
	(change_line_handler): Add parameter 'editing', and use it.  Bail
	early if the interpreter doesn't support editing.  Don't touch
	readline state if editing is off.
	(gdb_rl_callback_handler_remove, gdb_rl_callback_handler_install)
	(gdb_rl_callback_handler_reinstall): Assert the current UI is the
	main UI.
	(display_gdb_prompt): Don't call gdb_rl_callback_handler_remove if
	not using readline.  Check whether the current UI is using command
	editing instead of checking the async_command_editing_p global.
	(set_async_editing_command): Delete.
	(gdb_setup_readline): Add 'editing' parameter.  Only allow editing
	on the main UI.  Don't touch readline state if editing is off.
	(gdb_disable_readline): Don't touch readline state if editing is
	off.
	* event-top.h (gdb_setup_readline): Add 'int' parameter.
	(set_async_editing_command): Delete declaration.
	(change_line_handler, command_line_handler): Declare.
	(async_command_editing_p): Rename to ...
	(set_editing_cmd_var): ... this.
	* infrun.c (reinstall_readline_callback_handler_cleanup): Check
	whether the current UI has editing enabled rather than checking
	the async_command_editing_p global.
	* interps.c (interp_supports_command_editing): New function.
	* interps.h (interp_supports_command_editing_ftype): New typedef.
	(struct interp_procs) <supports_command_editing_proc>: New field.
	(interp_supports_command_editing): Declare.
	* mi/mi-interp.c (mi_interpreter_resume): Pass 0 to
	gdb_setup_readline.  Don't clear the async_command_editing_p
	global.  Update comments.
	* top.c (gdb_readline_wrapper_line, gdb_readline_wrapper): Check
	whether the current UI has editing enabled rather than checking
	the async_command_editing_p global.  Don't touch readline state if
	editing is off.
	(undo_terminal_modifications_before_exit): Switch to the main UI.
	Unconditionally call gdb_disable_readline.
	(set_editing): New function.
	(show_async_command_editing_p): Rename to ...
	(show_editing): ... this.  Show the state of the current UI.
	(_initialize_top): Adjust.
	* top.h (struct ui) <command_editing>: New field.
	* tui/tui-interp.c: Include cli/cli-interp.h.
	(tui_resume): Pass 1 to gdb_setup_readline.  Set the UI's
	input_handler.
	(tui_interp_procs): Install
	cli_interpreter_supports_command_editing.
	* tui/tui-io.c (tui_getc): Check whether the current UI has
	editing enabled rather than checking the async_command_editing_p
	global.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	PR mi/20034
	* gdb.mi/mi-editing.exp: New file.
---
 gdb/cli/cli-interp.c                | 16 ++++++-
 gdb/cli/cli-interp.h                | 25 ++++++++++
 gdb/event-top.c                     | 94 ++++++++++++++++++++-----------------
 gdb/event-top.h                     | 10 ++--
 gdb/infrun.c                        |  2 +-
 gdb/interps.c                       | 10 ++++
 gdb/interps.h                       | 11 +++++
 gdb/mi/mi-interp.c                  |  5 +-
 gdb/testsuite/gdb.mi/mi-editing.exp | 37 +++++++++++++++
 gdb/top.c                           | 46 +++++++++++++-----
 gdb/top.h                           |  5 ++
 gdb/tui/tui-interp.c                |  9 +++-
 gdb/tui/tui-io.c                    |  2 +-
 13 files changed, 201 insertions(+), 71 deletions(-)
 create mode 100644 gdb/cli/cli-interp.h
 create mode 100644 gdb/testsuite/gdb.mi/mi-editing.exp

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index cd33dd2..d67baf3 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -18,11 +18,13 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "cli-interp.h"
 #include "interps.h"
 #include "event-top.h"
 #include "ui-out.h"
 #include "cli-out.h"
 #include "top.h"		/* for "execute_command" */
+#include "event-top.h"
 #include "infrun.h"
 #include "observer.h"
 
@@ -199,6 +201,7 @@ cli_interpreter_init (struct interp *self, int top_level)
 static int
 cli_interpreter_resume (void *data)
 {
+  struct ui *ui = current_ui;
   struct cli_interp *cli = (struct cli_interp *) data;
   struct ui_file *stream;
 
@@ -215,7 +218,9 @@ cli_interpreter_resume (void *data)
       stream = NULL;
     }
 
-  gdb_setup_readline ();
+  gdb_setup_readline (1);
+
+  ui->input_handler = command_line_handler;
 
   if (stream != NULL)
     cli_out_set_stream (cli->cli_uiout, gdb_stdout);
@@ -255,6 +260,12 @@ cli_interpreter_exec (void *data, const char *command_str)
   return result;
 }
 
+int
+cli_interpreter_supports_command_editing (struct interp *interp)
+{
+  return 1;
+}
+
 static struct gdb_exception
 safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty)
 {
@@ -301,7 +312,8 @@ static const struct interp_procs cli_interp_procs = {
   cli_interpreter_exec,		/* exec_proc */
   cli_ui_out,			/* ui_out_proc */
   NULL,                       	/* set_logging_proc */
-  cli_command_loop            	/* command_loop_proc */
+  cli_command_loop,		/* command_loop_proc */
+  cli_interpreter_supports_command_editing, /* supports_command_editing_proc */
 };
 
 /* Factory for CLI interpreters.  */
diff --git a/gdb/cli/cli-interp.h b/gdb/cli/cli-interp.h
new file mode 100644
index 0000000..07b7505
--- /dev/null
+++ b/gdb/cli/cli-interp.h
@@ -0,0 +1,25 @@
+/* CLI Definitions for GDB, the GNU debugger.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef CLI_INTERP_H
+#define CLI_INTERP_H 1
+
+struct interp;
+
+extern int cli_interpreter_supports_command_editing (struct interp *interp);
+
+#endif
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 08eb89d..c84b3f4 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -48,8 +48,6 @@
 /* readline defines this.  */
 #undef savestring
 
-static void command_line_handler (char *rl);
-static void change_line_handler (void);
 static char *top_level_prompt (void);
 
 /* Signal handlers.  */
@@ -88,7 +86,7 @@ static void async_sigterm_handler (gdb_client_data arg);
    ezannoni: as of 1999-04-29 I expect that this
    variable will not be used after gdb is changed to use the event
    loop as default engine, and event-top.c is merged into top.c.  */
-int async_command_editing_p;
+int set_editing_cmd_var;
 
 /* This is used to display the notification of the completion of an
    asynchronous execution command.  */
@@ -236,34 +234,45 @@ cli_command_loop (void *data)
    therefore bypassing readline, and letting gdb handle the input
    itself, via gdb_readline_no_editing_callback.  Also it is used in
    the opposite case in which the user sets editing on again, by
-   restoring readline handling of the input.  */
-static void
-change_line_handler (void)
+   restoring readline handling of the input.
+
+   NOTE: this operates on input_fd, not instream.  If we are reading
+   commands from a file, instream will point to the file.  However, we
+   always read commands from a file with editing off.  This means that
+   the 'set editing on/off' will have effect only on the interactive
+   session.  */
+
+void
+change_line_handler (int editing)
 {
   struct ui *ui = current_ui;
 
-  /* NOTE: this operates on input_fd, not instream.  If we are reading
-     commands from a file, instream will point to the file.  However in
-     async mode, we always read commands from a file with editing
-     off.  This means that the 'set editing on/off' will have effect
-     only on the interactive session.  */
+  /* We can only have one instance of readline, so we only allow
+     editing on the main UI.  */
+  if (ui != main_ui)
+    return;
+
+  /* Don't try enabling editing if the interpreter doesn't support it
+     (e.g., MI).  */
+  if (!interp_supports_command_editing (top_level_interpreter ())
+      || !interp_supports_command_editing (command_interp ()))
+    return;
 
-  if (async_command_editing_p)
+  if (editing)
     {
+      gdb_assert (ui == main_ui);
+
       /* Turn on editing by using readline.  */
       ui->call_readline = gdb_rl_callback_read_char_wrapper;
-      ui->input_handler = command_line_handler;
     }
   else
     {
       /* Turn off editing by using gdb_readline_no_editing_callback.  */
-      gdb_rl_callback_handler_remove ();
+      if (ui->command_editing)
+	gdb_rl_callback_handler_remove ();
       ui->call_readline = gdb_readline_no_editing_callback;
-
-      /* Set up the command handler as well, in case we are called as
-         first thing from .gdbinit.  */
-      ui->input_handler = command_line_handler;
     }
+  ui->command_editing = editing;
 }
 
 /* The functions below are wrappers for rl_callback_handler_remove and
@@ -284,6 +293,8 @@ static int callback_handler_installed;
 void
 gdb_rl_callback_handler_remove (void)
 {
+  gdb_assert (current_ui == main_ui);
+
   rl_callback_handler_remove ();
   callback_handler_installed = 0;
 }
@@ -295,6 +306,8 @@ gdb_rl_callback_handler_remove (void)
 void
 gdb_rl_callback_handler_install (const char *prompt)
 {
+  gdb_assert (current_ui == main_ui);
+
   /* Calling rl_callback_handler_install resets readline's input
      buffer.  Calling this when we were already processing input
      therefore loses input.  */
@@ -309,6 +322,8 @@ gdb_rl_callback_handler_install (const char *prompt)
 void
 gdb_rl_callback_handler_reinstall (void)
 {
+  gdb_assert (current_ui == main_ui);
+
   if (!callback_handler_installed)
     {
       /* Passing NULL as prompt argument tells readline to not display
@@ -370,7 +385,8 @@ display_gdb_prompt (const char *new_prompt)
 	     the above two functions.  Calling
 	     rl_callback_handler_remove(), does the job.  */
 
-	  gdb_rl_callback_handler_remove ();
+	  if (current_ui->command_editing)
+	    gdb_rl_callback_handler_remove ();
 	  do_cleanups (old_chain);
 	  return;
 	}
@@ -383,7 +399,7 @@ display_gdb_prompt (const char *new_prompt)
   else
     actual_gdb_prompt = xstrdup (new_prompt);
 
-  if (async_command_editing_p)
+  if (current_ui->command_editing)
     {
       gdb_rl_callback_handler_remove ();
       gdb_rl_callback_handler_install (actual_gdb_prompt);
@@ -1214,21 +1230,13 @@ async_float_handler (gdb_client_data arg)
 }
 \f
 
-/* Called by do_setshow_command.  */
-void
-set_async_editing_command (char *args, int from_tty,
-			   struct cmd_list_element *c)
-{
-  change_line_handler ();
-}
-
 /* Set things up for readline to be invoked via the alternate
    interface, i.e. via a callback function
    (gdb_rl_callback_read_char), and hook up instream to the event
    loop.  */
 
 void
-gdb_setup_readline (void)
+gdb_setup_readline (int editing)
 {
   struct ui *ui = current_ui;
 
@@ -1243,32 +1251,28 @@ gdb_setup_readline (void)
   gdb_stdtarg = gdb_stderr; /* for moment */
   gdb_stdtargerr = gdb_stderr; /* for moment */
 
-  /* If the input stream is connected to a terminal, turn on
-     editing.  */
-  if (ISATTY (ui->instream))
+  /* If the input stream is connected to a terminal, turn on editing.
+     However, that is only allowed on the main UI, as we can only have
+     one instance of readline.  */
+  if (ISATTY (ui->instream) && editing && ui == main_ui)
     {
       /* Tell gdb that we will be using the readline library.  This
 	 could be overwritten by a command in .gdbinit like 'set
 	 editing on' or 'off'.  */
-      async_command_editing_p = 1;
-	  
+      ui->command_editing = 1;
+
       /* When a character is detected on instream by select or poll,
 	 readline will be invoked via this callback function.  */
       ui->call_readline = gdb_rl_callback_read_char_wrapper;
+
+      /* Tell readline to use the same input stream that gdb uses.  */
+      rl_instream = ui->instream;
     }
   else
     {
-      async_command_editing_p = 0;
+      ui->command_editing = 0;
       ui->call_readline = gdb_readline_no_editing_callback;
     }
-  
-  /* When readline has read an end-of-line character, it passes the
-     complete line to gdb for processing; command_line_handler is the
-     function that does this.  */
-  ui->input_handler = command_line_handler;
-
-  /* Tell readline to use the same input stream that gdb uses.  */
-  rl_instream = ui->instream;
 
   /* Now create the event source for this UI's input file descriptor.
      Another source is going to be the target program (inferior), but
@@ -1280,6 +1284,7 @@ gdb_setup_readline (void)
 /* Disable command input through the standard CLI channels.  Used in
    the suspend proc for interpreters that use the standard gdb readline
    interface, like the cli & the mi.  */
+
 void
 gdb_disable_readline (void)
 {
@@ -1298,6 +1303,7 @@ gdb_disable_readline (void)
   gdb_stdtargerr = NULL;
 #endif
 
-  gdb_rl_callback_handler_remove ();
+  if (ui->command_editing)
+    gdb_rl_callback_handler_remove ();
   delete_file_handler (ui->input_fd);
 }
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 4fe7737..dd0b4bc 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -28,12 +28,12 @@ struct cmd_list_element;
    FIXME: these should really go into top.h.  */
 
 extern void display_gdb_prompt (const char *new_prompt);
-void gdb_setup_readline (void);
-void gdb_disable_readline (void);
+extern void gdb_setup_readline (int);
+extern void gdb_disable_readline (void);
 extern void async_init_signals (void);
-extern void set_async_editing_command (char *args, int from_tty,
-				       struct cmd_list_element *c);
+extern void change_line_handler (int);
 
+extern void command_line_handler (char *rl);
 extern void command_handler (char *command);
 
 /* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT.  */
@@ -54,7 +54,7 @@ extern void async_enable_stdin (void);
 /* Exported variables from event-top.c.
    FIXME: these should really go into top.h.  */
 
-extern int async_command_editing_p;
+extern int set_editing_cmd_var;
 extern int exec_done_display_p;
 extern struct prompts the_prompts;
 extern void (*after_char_processing_hook) (void);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index ba7144a..eb2388b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3816,7 +3816,7 @@ reinstall_readline_callback_handler_cleanup (void *arg)
       return;
     }
 
-  if (async_command_editing_p && !sync_execution)
+  if (current_ui->command_editing && !sync_execution)
     gdb_rl_callback_handler_reinstall ();
 }
 
diff --git a/gdb/interps.c b/gdb/interps.c
index ca8512b..536630a 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -416,6 +416,16 @@ current_interp_command_loop (void)
   interp->procs->command_loop_proc (interp->data);
 }
 
+/* See interp.h  */
+
+int
+interp_supports_command_editing (struct interp *interp)
+{
+  if (interp->procs->supports_command_editing_proc != NULL)
+    return interp->procs->supports_command_editing_proc (interp);
+  return 0;
+}
+
 int
 interp_quiet_p (struct interp *interp)
 {
diff --git a/gdb/interps.h b/gdb/interps.h
index 3065fdf..4922544 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -54,6 +54,8 @@ typedef int (interp_set_logging_ftype) (struct interp *self, int start_log,
 					struct ui_file *out,
 					struct ui_file *logfile);
 
+typedef int (interp_supports_command_editing_ftype) (struct interp *self);
+
 struct interp_procs
 {
   interp_init_ftype *init_proc;
@@ -73,6 +75,11 @@ struct interp_procs
   interp_set_logging_ftype *set_logging_proc;
 
   interp_command_loop_ftype *command_loop_proc;
+
+  /* Returns true if this interpreter supports using the readline
+     library; false if it uses GDB's own simplified readline
+     emulation.  */
+  interp_supports_command_editing_ftype *supports_command_editing_proc;
 };
 
 extern struct interp *interp_new (const char *name,
@@ -114,6 +121,10 @@ extern struct interp *command_interp (void);
 
 extern void clear_interpreter_hooks (void);
 
+/* Returns true if INTERP supports using the readline library; false
+   if it uses GDB's own simplified form of readline.  */
+extern int interp_supports_command_editing (struct interp *interp);
+
 /* well-known interpreters */
 #define INTERP_CONSOLE		"console"
 #define INTERP_MI1             "mi1"
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 22250d9..8f6a57b 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -158,13 +158,10 @@ mi_interpreter_resume (void *data)
 
   /* As per hack note in mi_interpreter_init, swap in the output
      channels... */
-  gdb_setup_readline ();
+  gdb_setup_readline (0);
 
-  /* These overwrite some of the initialization done in
-     _intialize_event_loop.  */
   ui->call_readline = gdb_readline_no_editing_callback;
   ui->input_handler = mi_execute_command_input_handler;
-  async_command_editing_p = 0;
   /* 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
diff --git a/gdb/testsuite/gdb.mi/mi-editing.exp b/gdb/testsuite/gdb.mi/mi-editing.exp
new file mode 100644
index 0000000..b7c6bd1
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-editing.exp
@@ -0,0 +1,37 @@
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Regression test for PR mi/20034.  Trying to turn on "set editing"
+# when the top-level interpreter is MI would result in GDB/readline
+# aborting with:
+#
+# readline: readline_callback_read_char() called with no handler!
+# Aborted (core dumped)
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+mi_gdb_test "-interpreter-exec console \"set editing on\"" \
+  {=cmd-param-changed,param=\"editing\",.*\^done} \
+  "-interpreter-exec console \"set editing on\""
+
+mi_gdb_test "-interpreter-exec console \"show editing\"" \
+  ".*Editing of command lines as they are typed is off.*" \
+  "-interpreter-exec console \"show editing\""
diff --git a/gdb/top.c b/gdb/top.c
index 2e6cf31..7e82dcf 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -793,7 +793,7 @@ gdb_readline_wrapper_line (char *line)
      we're handling an asynchronous target event and running in the
      background, just before returning to the event loop to process
      further input (or more target events).  */
-  if (async_command_editing_p)
+  if (current_ui->command_editing)
     gdb_rl_callback_handler_remove ();
 }
 
@@ -813,7 +813,8 @@ gdb_readline_wrapper_cleanup (void *arg)
   struct gdb_readline_wrapper_cleanup *cleanup
     = (struct gdb_readline_wrapper_cleanup *) arg;
 
-  rl_already_prompted = cleanup->already_prompted_orig;
+  if (ui->command_editing)
+    rl_already_prompted = cleanup->already_prompted_orig;
 
   gdb_assert (ui->input_handler == gdb_readline_wrapper_line);
   ui->input_handler = cleanup->handler_orig;
@@ -851,7 +852,10 @@ gdb_readline_wrapper (const char *prompt)
   cleanup->handler_orig = ui->input_handler;
   ui->input_handler = gdb_readline_wrapper_line;
 
-  cleanup->already_prompted_orig = rl_already_prompted;
+  if (ui->command_editing)
+    cleanup->already_prompted_orig = rl_already_prompted;
+  else
+    cleanup->already_prompted_orig = 0;
 
   cleanup->target_is_async_orig = target_is_async_p ();
 
@@ -863,7 +867,8 @@ gdb_readline_wrapper (const char *prompt)
 
   /* Display our prompt and prevent double prompt display.  */
   display_gdb_prompt (prompt);
-  rl_already_prompted = 1;
+  if (ui->command_editing)
+    rl_already_prompted = 1;
 
   if (after_char_processing_hook)
     (*after_char_processing_hook) ();
@@ -1420,12 +1425,18 @@ quit_confirm (void)
 static void
 undo_terminal_modifications_before_exit (void)
 {
+  struct ui *saved_top_level = current_ui;
+
   target_terminal_ours ();
+
+  current_ui = main_ui;
+
 #if defined(TUI)
   tui_disable ();
 #endif
-  if (async_command_editing_p)
-    gdb_disable_readline ();
+  gdb_disable_readline ();
+
+  current_ui = saved_top_level;
 }
 
 
@@ -1739,13 +1750,24 @@ show_prompt (struct ui_file *file, int from_tty,
   fprintf_filtered (file, _("Gdb's prompt is \"%s\".\n"), value);
 }
 
+/* "set editing" command.  */
+
+static void
+set_editing (char *args, int from_tty, struct cmd_list_element *c)
+{
+  change_line_handler (set_editing_cmd_var);
+  /* Update the control variable so that MI's =cmd-param-changed event
+     shows the correct value. */
+  set_editing_cmd_var = current_ui->command_editing;
+}
+
 static void
-show_async_command_editing_p (struct ui_file *file, int from_tty,
-			      struct cmd_list_element *c, const char *value)
+show_editing (struct ui_file *file, int from_tty,
+	      struct cmd_list_element *c, const char *value)
 {
   fprintf_filtered (file, _("Editing of command lines as "
 			    "they are typed is %s.\n"),
-		    value);
+		    current_ui->command_editing ? _("on") : _("off"));
 }
 
 static void
@@ -1836,14 +1858,14 @@ used inside of user-defined commands that should not be repeated when\n\
 hitting return."));
 
   add_setshow_boolean_cmd ("editing", class_support,
-			   &async_command_editing_p, _("\
+			   &set_editing_cmd_var, _("\
 Set editing of command lines as they are typed."), _("\
 Show editing of command lines as they are typed."), _("\
 Use \"on\" to enable the editing, and \"off\" to disable it.\n\
 Without an argument, command line editing is enabled.  To edit, use\n\
 EMACS-like or VI-like commands like control-P or ESC."),
-			   set_async_editing_command,
-			   show_async_command_editing_p,
+			   set_editing,
+			   show_editing,
 			   &setlist, &showlist);
 
   add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\
diff --git a/gdb/top.h b/gdb/top.h
index dfef32c..2facd1e 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -55,6 +55,11 @@ struct ui
      processing.  */
   void (*input_handler) (char *);
 
+  /* True if this UI is using the readline library for command
+     editing; false if using GDB's own simple readline emulation, with
+     no editing support.  */
+  int command_editing;
+
   /* Each UI has its own independent set of interpreters.  */
   struct ui_interp_info *interp_info;
 
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 7691f8c..fc3c0ff 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -18,6 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
+#include "cli/cli-interp.h"
 #include "interps.h"
 #include "top.h"
 #include "event-top.h"
@@ -219,6 +220,7 @@ tui_init (struct interp *self, int top_level)
 static int
 tui_resume (void *data)
 {
+  struct ui *ui = current_ui;
   struct ui_file *stream;
 
   /* gdb_setup_readline will change gdb_stdout.  If the TUI was
@@ -232,7 +234,9 @@ tui_resume (void *data)
       stream = NULL;
     }
 
-  gdb_setup_readline ();
+  gdb_setup_readline (1);
+
+  ui->input_handler = command_line_handler;
 
   if (stream != NULL)
     cli_out_set_stream (tui_old_uiout, gdb_stdout);
@@ -274,7 +278,8 @@ static const struct interp_procs tui_interp_procs = {
   tui_exec,
   tui_ui_out,
   NULL,
-  cli_command_loop
+  cli_command_loop,
+  cli_interpreter_supports_command_editing,
 };
 
 /* Factory for TUI interpreters.  */
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 3fa32db..6f2d892 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -616,7 +616,7 @@ tui_getc (FILE *fp)
   if (ch == KEY_BACKSPACE)
     return '\b';
 
-  if (async_command_editing_p && key_is_start_sequence (ch))
+  if (current_ui->command_editing && key_is_start_sequence (ch))
     {
       int ch_pending;
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 29/34] Add new command to create extra console/mi UI channels
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (2 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 03/34] Introduce "struct ui" Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-26 18:34   ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 20/34] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
                   ` (31 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

With all the previous plumbing in place, it's now easy to add a
command that actually creates a new console/mi UI.

The intended use case is to make it possible and easy for MI frontends
to provide a fully featured GDB console to users, with readline
support, command line editing, history, etc., just like if gdb was
started on the command line.  Currently MI frontends have to try to
implement all of that theirselves and make use of "-interpreter-exec
console ...", which is far from perfect.  If you ever tried Eclipse's
gdb console window, you'll know what I mean...

Instead of trying to multiplex console through MI, this command let's
just leverage all the built in readline/editing support already inside
gdb.

The plan is for the MI frontend to start GDB in regular console mode,
running inside a terminal emulator widget embedded in Eclipse (which
already exists, for supporting the shell widget; other frontends have
similar widgets), and then tell GDB to run a full MI interpreter on an
extra / separate side channel, independent of the console.

My original prototype planned to do things the other way around --
start GDB in MI mode, and then start an extra CLI console on separate
tty.  I handed over that prototype to Marc Khouzam @ Eclipse CDT, and
after experimentation and discussion, we ended up concluding that
starting GDB in CLI mode instead was both easier and actually also
supported an interesting use case -- connect an Eclipse frontend to a
GDB that is already running outside Eclipse.

The current usage is "new-ui <interpreter> <tty>".

E.g., on a terminal run this scriplet:

 $ cat gdb-client
 #!/bin/bash

 reset
 tty
 tail -f /dev/null

 $ gdb-client
 /dev/pts/15

Now run gdb on another terminal, and tell it to start a MI interpreter
on the tty of the other terminal:

 ...
 (gdb) new-ui mi /dev/pts/15
 New UI allocated

Now back to the the gdb-client terminal, we'll get an MI prompt, ready
for MI input:

 /dev/pts/15
 =thread-group-added,id="i1"
 (gdb)

You can also start a new UI running a CLI, with:

 (gdb) new-ui console /dev/pts/15

Though note that this console won't support readline command editing.
It works as if "set editing off" was entered.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* interps.c (set_top_level_interpreter): New function, factored
	out from captured_main.
	(interpreter_completer): Make extern.
	* interps.h (set_top_level_interpreter, interpreter_completer):
	New declarations.
	(captured_main): Use set_top_level_interpreter.
	* top.c [!O_NOCTTY] (O_NOCTTY): Define as 0.
	(open_terminal_stream, new_ui_command): New functions.
	(init_main): Install the "new-ui" command.
---
 gdb/interps.c | 20 ++++++++++++--
 gdb/interps.h | 11 ++++++++
 gdb/main.c    | 12 +--------
 gdb/top.c     | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 113 insertions(+), 14 deletions(-)

diff --git a/gdb/interps.c b/gdb/interps.c
index acc6c1d..7f1f24c 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -312,6 +312,21 @@ interp_lookup (const char *name)
   return NULL;
 }
 
+/* See interps.h.  */
+
+void
+set_top_level_interpreter (const char *name)
+{
+  /* Find it.  */
+  struct interp *interp = interp_lookup (name);
+
+  if (interp == NULL)
+    error (_("Interpreter `%s' unrecognized"), name);
+  /* Install it.  */
+  if (!interp_set (interp, 1))
+    error (_("Interpreter `%s' failed to initialize."), name);
+}
+
 /* Returns the current interpreter.  */
 
 struct ui_out *
@@ -543,8 +558,9 @@ interpreter_exec_cmd (char *args, int from_tty)
   do_cleanups (cleanup);
 }
 
-/* List the possible interpreters which could complete the given text.  */
-static VEC (char_ptr) *
+/* See interps.h.  */
+
+VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
diff --git a/gdb/interps.h b/gdb/interps.h
index af97c6a..4890c68 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -96,6 +96,11 @@ extern int interp_set (struct interp *interp, int top_level);
    the interpreter.  */
 extern struct interp *interp_lookup (const char *name);
 
+/* Set the current UI's top level interpreter to the interpreter named
+   NAME.  Throws an error if NAME is not a known interpreter or the
+   interpreter fails to initialize.  */
+extern void set_top_level_interpreter (const char *name);
+
 extern struct ui_out *interp_ui_out (struct interp *interp);
 extern void *interp_data (struct interp *interp);
 extern const char *interp_name (struct interp *interp);
@@ -132,6 +137,12 @@ extern int interp_supports_command_editing (struct interp *interp);
    chance to e.g., print a prompt.  */
 extern void interp_pre_command_loop (struct interp *interp);
 
+/* List the possible interpreters which could complete the given
+   text.  */
+extern VEC (char_ptr) *interpreter_completer (struct cmd_list_element *ignore,
+					      const char *text,
+					      const char *word);
+
 /* well-known interpreters */
 #define INTERP_CONSOLE		"console"
 #define INTERP_MI1             "mi1"
diff --git a/gdb/main.c b/gdb/main.c
index 6475ce6..5477379 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -963,17 +963,7 @@ captured_main (void *data)
 
   /* Install the default UI.  All the interpreters should have had a
      look at things by now.  Initialize the default interpreter.  */
-
-  {
-    /* Find it.  */
-    struct interp *interp = interp_lookup (interpreter_p);
-
-    if (interp == NULL)
-      error (_("Interpreter `%s' unrecognized"), interpreter_p);
-    /* Install it.  */
-    if (!interp_set (interp, 1))
-      error (_("Interpreter `%s' failed to initialize."), interpreter_p);
-  }
+  set_top_level_interpreter (interpreter_p);
 
   /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets
      GDB retain the old MI1 interpreter startup behavior.  Output the
diff --git a/gdb/top.c b/gdb/top.c
index 7506c45..c978b9c 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -74,6 +74,10 @@
 # include "tui/tui.h"
 #endif
 
+#ifndef O_NOCTTY
+# define O_NOCTTY 0
+#endif
+
 extern void initialize_all_files (void);
 
 #define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
@@ -320,6 +324,77 @@ delete_ui (struct ui *todel)
   free_ui (ui);
 }
 
+/* Open file named NAME for read/write, making sure not to make it the
+   controlling terminal.  */
+
+static FILE *
+open_terminal_stream (const char *name)
+{
+  int fd;
+
+  fd = open (name, O_RDWR | O_NOCTTY);
+  if (fd < 0)
+    perror_with_name  (_("opening terminal failed"));
+
+  return fdopen (fd, "w+");
+}
+
+/* Implementation of the "new-ui" command.  */
+
+static void
+new_ui_command (char *args, int from_tty)
+{
+  struct ui *ui;
+  struct interp *interp;
+  FILE *stream[3] = { NULL, NULL, NULL };
+  int i;
+  int res;
+  int argc;
+  char **argv;
+  const char *interpreter_name;
+  const char *tty_name;
+  struct cleanup *back_to;
+  struct cleanup *streams_chain;
+
+  argv = gdb_buildargv (args);
+  back_to = make_cleanup_freeargv (argv);
+  argc = countargv (argv);
+
+  if (argc < 2)
+    error (_("usage: new-ui <interpreter> <tty>"));
+
+  interpreter_name = argv[0];
+  tty_name = argv[1];
+
+  streams_chain = make_cleanup (null_cleanup, NULL);
+
+  /* Open specified terminal, once for each of
+     stdin/stdout/stderr.  */
+  for (i = 0; i < 3; i++)
+    {
+      stream[i] = open_terminal_stream (tty_name);
+      make_cleanup_fclose (stream[i]);
+    }
+
+  ui = new_ui (stream[0], stream[1], stream[2]);
+
+  discard_cleanups (streams_chain);
+
+  ui->async = 1;
+
+  make_cleanup (restore_ui_cleanup, current_ui);
+  current_ui = ui;
+
+  set_top_level_interpreter (interpreter_name);
+
+  interp_pre_command_loop (top_level_interpreter ());
+
+  /* This restores the previous UI.  */
+  do_cleanups (back_to);
+
+  printf_unfiltered ("New UI allocated\n");
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
@@ -1923,6 +1998,8 @@ set_history_filename (char *args, int from_tty, struct cmd_list_element *c)
 static void
 init_main (void)
 {
+  struct cmd_list_element *c;
+
   /* Initialize the prompt to a simple "(gdb) " prompt or to whatever
      the DEFAULT_PROMPT is.  */
   set_prompt (DEFAULT_PROMPT);
@@ -2046,7 +2123,6 @@ When set, GDB uses the specified path to search for data files."),
                            set_gdb_datadir, show_gdb_datadir,
                            &setlist,
                            &showlist);
-
   add_setshow_auto_boolean_cmd ("interactive-mode", class_support,
                                 &interactive_mode, _("\
 Set whether GDB's standard input is a terminal."), _("\
@@ -2060,6 +2136,12 @@ input settings."),
                         NULL,
                         show_interactive_mode,
                         &setlist, &showlist);
+
+  c = add_cmd ("new-ui", class_support, new_ui_command, _("\
+Create a new UI.  It takes two arguments:\n\
+The first argument is the name of the interpreter to run.\n\
+The second argument is the terminal the UI runs on.\n"), &cmdlist);
+  set_cmd_completer (c, interpreter_completer);
 }
 
 void
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 01/34] Prepare gdb.python/mi-py-events.exp for Python/MI in separate channels
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (9 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 16/34] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:36 ` [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI Pedro Alves
                   ` (24 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

Similarly to 5068630ad34dce5fefbe68d70d3a50cd8b92f71e
(gdb.python/py-events.exp and normal_stop observers ordering) [1],
this commit makes the gdb.python/py-mi-events.exp test not rely on
order in which MI and Python observers run, or even on where each
observer sends its output to.

This shows up as a problem when testing with MI running as a separate
terminal, for example, where Python event output and MI output go to
different channels, even.  But in any case, relying on the order in
which observers run is always going to be fragile.

The fix is to save the string output in the handlers in some variables
and then having MI print them explicitly, instead of printing them
directly from the Python events.

Tested on x86_64 Fedora 23.

https://sourceware.org/ml/gdb-patches/2015-07/msg00290.html

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.python/py-mi-events-gdb.py (stop_handler_str)
	(cont_handler_str): New.
	(signal_stop_handler): Set stop_handler_str instead of printing to
	stdout.
	(continue_handler): Set cont_handler_str instead of printing to
	stdout.
	* gdb.python/py-mi-events.exp: Ues mi_execute_to instead of
	mi_send_resuming_command.  Print stop_handler_str and
	cont_handler_str instead of expecting the python events print
	directly.
---
 gdb/testsuite/gdb.python/py-mi-events-gdb.py | 12 ++++++++----
 gdb/testsuite/gdb.python/py-mi-events.exp    | 21 ++++++++++++---------
 2 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/gdb/testsuite/gdb.python/py-mi-events-gdb.py b/gdb/testsuite/gdb.python/py-mi-events-gdb.py
index 975ff2f..2bcb1fa 100644
--- a/gdb/testsuite/gdb.python/py-mi-events-gdb.py
+++ b/gdb/testsuite/gdb.python/py-mi-events-gdb.py
@@ -19,19 +19,23 @@
 
 import gdb
 
+stop_handler_str = ""
+cont_handler_str = ""
 
 def signal_stop_handler (event):
     """Stop event handler"""
     assert (isinstance (event, gdb.StopEvent))
-    print ("stop_handler")
-    print (gdb.execute("info break", False, True))
+    global stop_handler_str
+    stop_handler_str = "stop_handler\n"
+    stop_handler_str += gdb.execute("info break", False, True)
 
 
 def continue_handler (event):
     """Continue event handler"""
     assert (isinstance (event, gdb.ContinueEvent))
-    print ("continue_handler")
-    print (gdb.execute("info break", False, True))
+    global cont_handler_str
+    cont_handler_str = "continue_handler\n"
+    cont_handler_str += gdb.execute("info break", False, True)
 
 
 class test_events (gdb.Command):
diff --git a/gdb/testsuite/gdb.python/py-mi-events.exp b/gdb/testsuite/gdb.python/py-mi-events.exp
index 6f063e1..d20ae98 100644
--- a/gdb/testsuite/gdb.python/py-mi-events.exp
+++ b/gdb/testsuite/gdb.python/py-mi-events.exp
@@ -58,14 +58,16 @@ mi_gdb_test "test-events" \
     "register events"
 
 
+set lineno [gdb_get_line_number "i++;"]
+
 # set a breakpoint into the for loop
-mi_gdb_test "break ${srcfile}:[gdb_get_line_number "i++;"]" \
+mi_gdb_test "break ${srcfile}:$lineno" \
     ".*Breakpoint $decimal at 0x\[0-9a-fA-F\]+: file .*${srcfile}.*\\\.*\\^done" \
     "set the breakpoint"
 
 
 # resume the program
-mi_send_resuming_command "exec-continue" "continue"
+mi_execute_to "exec-continue" "breakpoint-hit" "main" "" ".*$srcfile" "$lineno" { "" "disp=\"keep\"" } "continue"
 
 
 # test the python event handlers execution. The following checks are performed:
@@ -73,12 +75,13 @@ mi_send_resuming_command "exec-continue" "continue"
 # - the continue handler prints "info breakpoints" output in console format
 # - breakpoint is hit and python stop handler is executed
 # - the stop handler prints "info breakpoints" output in console format
-mi_gdb_test "" ".*continue_handler.*
-.*Num.*Type.*Disp.*Enb.*Address.*\
-.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*
-.*stop_handler.*
-.*Num.*Type.*Disp.*Enb.*Address.*\
-.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*" \
-"check python continue and stop handlers"
+
+mi_gdb_test "python print (stop_handler_str)" \
+".*stop_handler.*Num.*Type.*Disp.*Enb.*Address.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*" \
+"python stop handler ran"
+
+mi_gdb_test "python print (cont_handler_str)" \
+".*continue_handler.*Num.*Type.*Disp.*Enb.*Address.*$decimal.*breakpoint.*keep.*y.* 0x\[0-9a-fA-F\]+.*${srcfile}.*" \
+"python continue handler ran"
 
 mi_gdb_exit
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 02/34] [Ada catchpoints] Fix "warning: failed to get exception name: No definition of \"e.full_name\" in current context" Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-07-01 11:02   ` Thomas Preudhomme
  2016-05-06 12:35 ` [PATCH v3 03/34] Introduce "struct ui" Pedro Alves
                   ` (33 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

I noticed that if we step into an inline function, step_1 never
reaches proceed, and thus nevers sets the thread's
tp->control.command_interp.  Because of that,
should_print_stop_to_console fails to determine that is should print
stop output to the console.

The fix is to set the thread's command_interp earlier.  However, I
realized that we can move that field to the thread_fsm, given that its
lifetime is exactly the same as thread_fsm.  So the patch plumbs all
fsms constructors to take the command interp and store it in the
thread_fsm.

We can see the fix in action, with e.g., the gdb.opt/inline-cmds.exp
test, and issuing a step when stopped at line 67:

 &"s\n"
 ^running
 *running,thread-id="all"
 (gdb)
 ~"67\t  result = func2 ();\n"
 *stopped,reason="end-stepping-range",frame={addr="0x00000000004004d0",func="main",args=[],file="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",fullname="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",line="67"},thread-id="1",stopped-threads="all",core="0"
 (gdb)
 s
 &"s\n"
 ^running
 *running,thread-id="all"
 (gdb)
+ ~"func2 () at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c:67\n"
+ ~"67\t  result = func2 ();\n"
 *stopped,reason="end-stepping-range",frame={addr="0x00000000004004d0",func="func2",args=[],file="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",fullname="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-cmds.c",line="67"},thread-id="1",stopped-threads="all",core="0"
 (gdb)

(The inline-cmds.exp command is adjusted to exercise this.)

(Due to the follow_fork change, this also fixes "next N" across a fork
with "set follow-fork child" with "set detach-on-fork on".  Commands
that rely on internal breakpoints, like "finish" will still require
more work to migrate breakpoints etc. to the child thread.)

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* breakpoint.c (new_until_break_fsm): Add 'cmd_interp' parameter.
	(until_break_fsm_should_stop, until_break_fsm_clean_up): Add
	thread parameter.
	(until_break_command): Pass command interpreter to thread fsm
	ctor.
	* cli/cli-interp.c (should_print_stop_to_console): Adjust.
	* gdbthread.h (struct thread_control_state) <command_interp>:
	Delete field.
	* infcall.c (new_call_thread_fsm): Add 'cmd_interp' parameter.
	Pass it down.
	(call_thread_fsm_should_stop): Add thread parameter.
	(call_function_by_hand_dummy): Pass command interpreter to thread
	fsm ctor.  Pass thread pointer to fsm clean up method.
	* infcmd.c: Include interps.h.
	(struct step_command_fsm) <thread>: Delete field.
	(new_step_command_fsm): Add 'cmd_interp' parameter.  Pass it down.
	(step_command_fsm_prepare): Remove references to fsm's thread
	field.
	(step_1): Pass command interpreter to thread
	fsm ctor.  Pass thread pointer to fsm clean up method.
	(step_command_fsm_should_stop, step_command_fsm_clean_up): Add
	thread parameter and use it.
	(new_until_next_fsm): Add 'cmd_interp' parameter.  Pass it down.
	(until_next_fsm_should_stop, until_next_fsm_clean_up): Add thread
	parameter and use it.
	(until_next_command): Pass command interpreter to thread fsm ctor.
	(struct finish_command_fsm) <thread>: Delete field.
	(finish_command_fsm_ops): Add NULL slot for should_notify_stop.
	(new_finish_command_fsm): Add 'cmd_interp' parameter and pass it
	down.  Remove thread parameter and adjust.
	(finish_command_fsm_should_stop, finish_command_fsm_clean_up): Add
	thread parameter and use it.
	(finish_command): Pass command interpreter to thread fsm ctor.
	Don't pass thread.
	* infrun.c (follow_fork): Move thread fsm to child fork instead of
	command interpreter, only.
	(clear_proceed_status_thread): Remove reference to command_interp.
	(proceed): Don't record the thread's command interpreter.
	(clean_up_just_stopped_threads_fsms): Pass thread to fsm clean_up
	method.
	(fetch_inferior_event): Pass thread to fsm should_stop method.
	* thread-fsm.c (thread_fsm_ctor): Add 'cmd_interp' parameter.
	Store it.
	(thread_fsm_clean_up, thread_fsm_should_stop): Add thread
	parameter and pass it down.
	* thread-fsm.h (struct thread_fsm) <command_interp>: New field.
	(struct thread_fsm_ops) <clean_up, should_stop>: Add thread
	parameter.
	(thread_fsm_ctor): Add 'cmd_interp' parameter.
	(thread_fsm_clean_up, thread_fsm_should_stop): Add thread
	parameter.
	* thread.c (thread_cancel_execution_command): Pass thread to
	thread fsm clean_up method.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.opt/inline-cmds.c: Add "set mi break here" marker.
	* gdb.opt/inline-cmds.exp: Add MI tests.
---
 gdb/breakpoint.c                      | 19 +++++----
 gdb/cli/cli-interp.c                  |  7 ++--
 gdb/gdbthread.h                       |  5 ---
 gdb/infcall.c                         | 14 ++++---
 gdb/infcmd.c                          | 74 +++++++++++++++++------------------
 gdb/infrun.c                          | 23 ++++-------
 gdb/testsuite/gdb.opt/inline-cmds.c   |  2 +-
 gdb/testsuite/gdb.opt/inline-cmds.exp | 62 +++++++++++++++++++++++++++++
 gdb/thread-fsm.c                      | 12 +++---
 gdb/thread-fsm.h                      | 23 ++++++++---
 gdb/thread.c                          |  2 +-
 11 files changed, 153 insertions(+), 90 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a28e956..d181597 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -11614,8 +11614,10 @@ struct until_break_fsm
   struct breakpoint *caller_breakpoint;
 };
 
-static void until_break_fsm_clean_up (struct thread_fsm *self);
-static int until_break_fsm_should_stop (struct thread_fsm *self);
+static void until_break_fsm_clean_up (struct thread_fsm *self,
+				      struct thread_info *thread);
+static int until_break_fsm_should_stop (struct thread_fsm *self,
+					struct thread_info *thread);
 static enum async_reply_reason
   until_break_fsm_async_reply_reason (struct thread_fsm *self);
 
@@ -11633,14 +11635,14 @@ static struct thread_fsm_ops until_break_fsm_ops =
 /* Allocate a new until_break_command_fsm.  */
 
 static struct until_break_fsm *
-new_until_break_fsm (int thread,
+new_until_break_fsm (struct interp *cmd_interp, int thread,
 		     struct breakpoint *location_breakpoint,
 		     struct breakpoint *caller_breakpoint)
 {
   struct until_break_fsm *sm;
 
   sm = XCNEW (struct until_break_fsm);
-  thread_fsm_ctor (&sm->thread_fsm, &until_break_fsm_ops);
+  thread_fsm_ctor (&sm->thread_fsm, &until_break_fsm_ops, cmd_interp);
 
   sm->thread = thread;
   sm->location_breakpoint = location_breakpoint;
@@ -11653,10 +11655,10 @@ new_until_break_fsm (int thread,
    until(location)/advance commands.  */
 
 static int
-until_break_fsm_should_stop (struct thread_fsm *self)
+until_break_fsm_should_stop (struct thread_fsm *self,
+			     struct thread_info *tp)
 {
   struct until_break_fsm *sm = (struct until_break_fsm *) self;
-  struct thread_info *tp = inferior_thread ();
 
   if (bpstat_find_breakpoint (tp->control.stop_bpstat,
 			      sm->location_breakpoint) != NULL
@@ -11672,7 +11674,8 @@ until_break_fsm_should_stop (struct thread_fsm *self)
    until(location)/advance commands.  */
 
 static void
-until_break_fsm_clean_up (struct thread_fsm *self)
+until_break_fsm_clean_up (struct thread_fsm *self,
+			  struct thread_info *thread)
 {
   struct until_break_fsm *sm = (struct until_break_fsm *) self;
 
@@ -11794,7 +11797,7 @@ until_break_command (char *arg, int from_tty, int anywhere)
 						    stack_frame_id, bp_until);
   make_cleanup_delete_breakpoint (location_breakpoint);
 
-  sm = new_until_break_fsm (tp->global_num,
+  sm = new_until_break_fsm (command_interp (), tp->global_num,
 			    location_breakpoint, caller_breakpoint);
   tp->thread_fsm = &sm->thread_fsm;
 
diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index bbe287c..e6f104b 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -77,10 +77,9 @@ should_print_stop_to_console (struct interp *console_interp,
 {
   if ((bpstat_what (tp->control.stop_bpstat).main_action
        == BPSTAT_WHAT_STOP_NOISY)
-      || !(tp->thread_fsm != NULL
-	   && thread_fsm_finished_p (tp->thread_fsm))
-      || (tp->control.command_interp != NULL
-	  && tp->control.command_interp == console_interp))
+      || tp->thread_fsm == NULL
+      || tp->thread_fsm->command_interp == console_interp
+      || !thread_fsm_finished_p (tp->thread_fsm))
     return 1;
   return 0;
 }
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index bdd2bb0..af2dc86 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -136,11 +136,6 @@ struct thread_control_state
      at.  */
   bpstat stop_bpstat;
 
-  /* The interpreter that issued the execution command.  NULL if the
-     thread was resumed as a result of a command applied to some other
-     thread (e.g., "next" with scheduler-locking off).  */
-  struct interp *command_interp;
-
   /* Whether the command that started the thread was a stepping
      command.  This is used to decide whether "set scheduler-locking
      step" behaves like "on" or "off".  */
diff --git a/gdb/infcall.c b/gdb/infcall.c
index d491f95..8199bdd 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -470,7 +470,8 @@ struct call_thread_fsm
   struct ui *waiting_ui;
 };
 
-static int call_thread_fsm_should_stop (struct thread_fsm *self);
+static int call_thread_fsm_should_stop (struct thread_fsm *self,
+					struct thread_info *thread);
 static int call_thread_fsm_should_notify_stop (struct thread_fsm *self);
 
 /* call_thread_fsm's vtable.  */
@@ -488,7 +489,7 @@ 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 ui *waiting_ui,
+new_call_thread_fsm (struct ui *waiting_ui, struct interp *cmd_interp,
 		     struct gdbarch *gdbarch, struct value *function,
 		     struct type *value_type,
 		     int struct_return_p, CORE_ADDR struct_addr)
@@ -496,7 +497,7 @@ new_call_thread_fsm (struct ui *waiting_ui,
   struct call_thread_fsm *sm;
 
   sm = XCNEW (struct call_thread_fsm);
-  thread_fsm_ctor (&sm->thread_fsm, &call_thread_fsm_ops);
+  thread_fsm_ctor (&sm->thread_fsm, &call_thread_fsm_ops, cmd_interp);
 
   sm->return_meta_info.gdbarch = gdbarch;
   sm->return_meta_info.function = function;
@@ -512,7 +513,8 @@ new_call_thread_fsm (struct ui *waiting_ui,
 /* Implementation of should_stop method for infcalls.  */
 
 static int
-call_thread_fsm_should_stop (struct thread_fsm *self)
+call_thread_fsm_should_stop (struct thread_fsm *self,
+			     struct thread_info *thread)
 {
   struct call_thread_fsm *f = (struct call_thread_fsm *) self;
 
@@ -1135,7 +1137,7 @@ 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 (current_ui,
+    sm = new_call_thread_fsm (current_ui, command_interp (),
 			      gdbarch, function,
 			      values_type,
 			      struct_return || hidden_first_param_p,
@@ -1167,7 +1169,7 @@ call_function_by_hand_dummy (struct value *function,
 
 	    /* Clean up / destroy the call FSM, and restore the
 	       original one.  */
-	    thread_fsm_clean_up (tp->thread_fsm);
+	    thread_fsm_clean_up (tp->thread_fsm, tp);
 	    thread_fsm_delete (tp->thread_fsm);
 	    tp->thread_fsm = saved_sm;
 
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index a1d4d5d..6b1d6a4 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -57,6 +57,7 @@
 #include "infcall.h"
 #include "thread-fsm.h"
 #include "top.h"
+#include "interps.h"
 
 /* Local functions: */
 
@@ -925,13 +926,12 @@ struct step_command_fsm
 
   /* If true, this is a stepi/nexti, otherwise a step/step.  */
   int single_inst;
-
-  /* The thread that the command was run on.  */
-  int thread;
 };
 
-static void step_command_fsm_clean_up (struct thread_fsm *self);
-static int step_command_fsm_should_stop (struct thread_fsm *self);
+static void step_command_fsm_clean_up (struct thread_fsm *self,
+				       struct thread_info *thread);
+static int step_command_fsm_should_stop (struct thread_fsm *self,
+					 struct thread_info *thread);
 static enum async_reply_reason
   step_command_fsm_async_reply_reason (struct thread_fsm *self);
 
@@ -949,12 +949,12 @@ static struct thread_fsm_ops step_command_fsm_ops =
 /* Allocate a new step_command_fsm.  */
 
 static struct step_command_fsm *
-new_step_command_fsm (void)
+new_step_command_fsm (struct interp *cmd_interp)
 {
   struct step_command_fsm *sm;
 
   sm = XCNEW (struct step_command_fsm);
-  thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops);
+  thread_fsm_ctor (&sm->thread_fsm, &step_command_fsm_ops, cmd_interp);
 
   return sm;
 }
@@ -970,7 +970,6 @@ step_command_fsm_prepare (struct step_command_fsm *sm,
   sm->skip_subroutines = skip_subroutines;
   sm->single_inst = single_inst;
   sm->count = count;
-  sm->thread = thread->global_num;
 
   /* Leave the si command alone.  */
   if (!sm->single_inst || sm->skip_subroutines)
@@ -1010,7 +1009,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
   /* Setup the execution command state machine to handle all the COUNT
      steps.  */
   thr = inferior_thread ();
-  step_sm = new_step_command_fsm ();
+  step_sm = new_step_command_fsm (command_interp ());
   thr->thread_fsm = &step_sm->thread_fsm;
 
   step_command_fsm_prepare (step_sm, skip_subroutines,
@@ -1028,7 +1027,7 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
 
       /* Stepped into an inline frame.  Pretend that we've
 	 stopped.  */
-      thread_fsm_clean_up (thr->thread_fsm);
+      thread_fsm_clean_up (thr->thread_fsm, thr);
       proceeded = normal_stop ();
       if (!proceeded)
 	inferior_event_handler (INF_EXEC_COMPLETE, NULL);
@@ -1043,10 +1042,9 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
    will need to keep going.  */
 
 static int
-step_command_fsm_should_stop (struct thread_fsm *self)
+step_command_fsm_should_stop (struct thread_fsm *self, struct thread_info *tp)
 {
   struct step_command_fsm *sm = (struct step_command_fsm *) self;
-  struct thread_info *tp = find_thread_global_id (sm->thread);
 
   if (tp->control.stop_step)
     {
@@ -1064,12 +1062,12 @@ step_command_fsm_should_stop (struct thread_fsm *self)
 /* Implementation of the 'clean_up' FSM method for stepping commands.  */
 
 static void
-step_command_fsm_clean_up (struct thread_fsm *self)
+step_command_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
 {
   struct step_command_fsm *sm = (struct step_command_fsm *) self;
 
   if (!sm->single_inst || sm->skip_subroutines)
-    delete_longjmp_breakpoint (sm->thread);
+    delete_longjmp_breakpoint (thread->global_num);
 }
 
 /* Implementation of the 'async_reply_reason' FSM method for stepping
@@ -1411,8 +1409,10 @@ struct until_next_fsm
   int thread;
 };
 
-static int until_next_fsm_should_stop (struct thread_fsm *self);
-static void until_next_fsm_clean_up (struct thread_fsm *self);
+static int until_next_fsm_should_stop (struct thread_fsm *self,
+				       struct thread_info *thread);
+static void until_next_fsm_clean_up (struct thread_fsm *self,
+				     struct thread_info *thread);
 static enum async_reply_reason
   until_next_fsm_async_reply_reason (struct thread_fsm *self);
 
@@ -1430,12 +1430,12 @@ static struct thread_fsm_ops until_next_fsm_ops =
 /* Allocate a new until_next_fsm.  */
 
 static struct until_next_fsm *
-new_until_next_fsm (int thread)
+new_until_next_fsm (struct interp *cmd_interp, int thread)
 {
   struct until_next_fsm *sm;
 
   sm = XCNEW (struct until_next_fsm);
-  thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops);
+  thread_fsm_ctor (&sm->thread_fsm, &until_next_fsm_ops, cmd_interp);
 
   sm->thread = thread;
 
@@ -1446,10 +1446,9 @@ new_until_next_fsm (int thread)
    no arg) command.  */
 
 static int
-until_next_fsm_should_stop (struct thread_fsm *self)
+until_next_fsm_should_stop (struct thread_fsm *self,
+			    struct thread_info *tp)
 {
-  struct thread_info *tp = inferior_thread ();
-
   if (tp->control.stop_step)
     thread_fsm_set_finished (self);
 
@@ -1460,11 +1459,11 @@ until_next_fsm_should_stop (struct thread_fsm *self)
    arg) command.  */
 
 static void
-until_next_fsm_clean_up (struct thread_fsm *self)
+until_next_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
 {
   struct until_next_fsm *sm = (struct until_next_fsm *) self;
 
-  delete_longjmp_breakpoint (sm->thread);
+  delete_longjmp_breakpoint (thread->global_num);
 }
 
 /* Implementation of the 'async_reply_reason' FSM method for the until
@@ -1534,7 +1533,7 @@ until_next_command (int from_tty)
   set_longjmp_breakpoint (tp, get_frame_id (frame));
   old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
 
-  sm = new_until_next_fsm (tp->global_num);
+  sm = new_until_next_fsm (command_interp (), tp->global_num);
   tp->thread_fsm = &sm->thread_fsm;
   discard_cleanups (old_chain);
 
@@ -1729,9 +1728,6 @@ struct finish_command_fsm
   /* The base class.  */
   struct thread_fsm thread_fsm;
 
-  /* The thread that was current when the command was executed.  */
-  int thread;
-
   /* The momentary breakpoint set at the function's return address in
      the caller.  */
   struct breakpoint *breakpoint;
@@ -1744,8 +1740,10 @@ struct finish_command_fsm
   struct return_value_info return_value;
 };
 
-static int finish_command_fsm_should_stop (struct thread_fsm *self);
-static void finish_command_fsm_clean_up (struct thread_fsm *self);
+static int finish_command_fsm_should_stop (struct thread_fsm *self,
+					   struct thread_info *thread);
+static void finish_command_fsm_clean_up (struct thread_fsm *self,
+					 struct thread_info *thread);
 static struct return_value_info *
   finish_command_fsm_return_value (struct thread_fsm *self);
 static enum async_reply_reason
@@ -1760,19 +1758,18 @@ static struct thread_fsm_ops finish_command_fsm_ops =
   finish_command_fsm_should_stop,
   finish_command_fsm_return_value,
   finish_command_fsm_async_reply_reason,
+  NULL, /* should_notify_stop */
 };
 
 /* Allocate a new finish_command_fsm.  */
 
 static struct finish_command_fsm *
-new_finish_command_fsm (int thread)
+new_finish_command_fsm (struct interp *cmd_interp)
 {
   struct finish_command_fsm *sm;
 
   sm = XCNEW (struct finish_command_fsm);
-  thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops);
-
-  sm->thread = thread;
+  thread_fsm_ctor (&sm->thread_fsm, &finish_command_fsm_ops, cmd_interp);
 
   return sm;
 }
@@ -1783,11 +1780,11 @@ new_finish_command_fsm (int thread)
    marks the FSM finished.  */
 
 static int
-finish_command_fsm_should_stop (struct thread_fsm *self)
+finish_command_fsm_should_stop (struct thread_fsm *self,
+				struct thread_info *tp)
 {
   struct finish_command_fsm *f = (struct finish_command_fsm *) self;
   struct return_value_info *rv = &f->return_value;
-  struct thread_info *tp = find_thread_global_id (f->thread);
 
   if (f->function != NULL
       && bpstat_find_breakpoint (tp->control.stop_bpstat,
@@ -1825,7 +1822,8 @@ finish_command_fsm_should_stop (struct thread_fsm *self)
    commands.  */
 
 static void
-finish_command_fsm_clean_up (struct thread_fsm *self)
+finish_command_fsm_clean_up (struct thread_fsm *self,
+			     struct thread_info *thread)
 {
   struct finish_command_fsm *f = (struct finish_command_fsm *) self;
 
@@ -1834,7 +1832,7 @@ finish_command_fsm_clean_up (struct thread_fsm *self)
       delete_breakpoint (f->breakpoint);
       f->breakpoint = NULL;
     }
-  delete_longjmp_breakpoint (f->thread);
+  delete_longjmp_breakpoint (thread->global_num);
 }
 
 /* Implementation of the 'return_value' FSM method for the finish
@@ -1980,7 +1978,7 @@ finish_command (char *arg, int from_tty)
 
   tp = inferior_thread ();
 
-  sm = new_finish_command_fsm (tp->global_num);
+  sm = new_finish_command_fsm (command_interp ());
 
   tp->thread_fsm = &sm->thread_fsm;
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index cc793c3..a7b5a60 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -683,7 +683,7 @@ follow_fork (void)
   CORE_ADDR step_range_start = 0;
   CORE_ADDR step_range_end = 0;
   struct frame_id step_frame_id = { 0 };
-  struct interp *command_interp = NULL;
+  struct thread_fsm *thread_fsm = NULL;
 
   if (!non_stop)
     {
@@ -735,7 +735,7 @@ follow_fork (void)
 	    step_frame_id = tp->control.step_frame_id;
 	    exception_resume_breakpoint
 	      = clone_momentary_breakpoint (tp->control.exception_resume_breakpoint);
-	    command_interp = tp->control.command_interp;
+	    thread_fsm = tp->thread_fsm;
 
 	    /* For now, delete the parent's sr breakpoint, otherwise,
 	       parent/child sr breakpoints are considered duplicates,
@@ -747,7 +747,7 @@ follow_fork (void)
 	    tp->control.step_range_end = 0;
 	    tp->control.step_frame_id = null_frame_id;
 	    delete_exception_resume_breakpoint (tp);
-	    tp->control.command_interp = NULL;
+	    tp->thread_fsm = NULL;
 	  }
 
 	parent = inferior_ptid;
@@ -793,7 +793,7 @@ follow_fork (void)
 		    tp->control.step_frame_id = step_frame_id;
 		    tp->control.exception_resume_breakpoint
 		      = exception_resume_breakpoint;
-		    tp->control.command_interp = command_interp;
+		    tp->thread_fsm = thread_fsm;
 		  }
 		else
 		  {
@@ -2852,7 +2852,6 @@ clear_proceed_status_thread (struct thread_info *tp)
 
   tp->control.proceed_to_finish = 0;
 
-  tp->control.command_interp = NULL;
   tp->control.stepping_command = 0;
 
   /* Discard any remaining commands or status from previous stop.  */
@@ -3046,14 +3045,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
   if (siggnal != GDB_SIGNAL_DEFAULT)
     tp->suspend.stop_signal = siggnal;
 
-  /* Record the interpreter that issued the execution command that
-     caused this thread to resume.  If the top level interpreter is
-     MI/async, and the execution command was a CLI command
-     (next/step/etc.), we'll want to print stop event output to the MI
-     console channel (the stepped-to line, etc.), as if the user
-     entered the execution command on a real GDB console.  */
-  tp->control.command_interp = command_interp ();
-
   resume_ptid = user_visible_resume_ptid (tp->control.stepping_command);
 
   /* If an exception is thrown from this point on, make sure to
@@ -3827,7 +3818,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
   struct thread_info *thr = ecs->event_thread;
 
   if (thr != NULL && thr->thread_fsm != NULL)
-    thread_fsm_clean_up (thr->thread_fsm);
+    thread_fsm_clean_up (thr->thread_fsm, thr);
 
   if (!non_stop)
     {
@@ -3839,7 +3830,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs)
 	    continue;
 
 	  switch_to_thread (thr->ptid);
-	  thread_fsm_clean_up (thr->thread_fsm);
+	  thread_fsm_clean_up (thr->thread_fsm, thr);
 	}
 
       if (ecs->event_thread != NULL)
@@ -3997,7 +3988,7 @@ fetch_inferior_event (void *client_data)
 	  struct thread_fsm *thread_fsm = thr->thread_fsm;
 
 	  if (thread_fsm != NULL)
-	    should_stop = thread_fsm_should_stop (thread_fsm);
+	    should_stop = thread_fsm_should_stop (thread_fsm, thr);
 	}
 
       if (!should_stop)
diff --git a/gdb/testsuite/gdb.opt/inline-cmds.c b/gdb/testsuite/gdb.opt/inline-cmds.c
index 20e1d0b..59631d7 100644
--- a/gdb/testsuite/gdb.opt/inline-cmds.c
+++ b/gdb/testsuite/gdb.opt/inline-cmds.c
@@ -61,7 +61,7 @@ int main (void)
   int val;
 
   x = 7;
-  y = 8;
+  y = 8; /* set mi break here */
 
   result = func1 ();
   result = func2 ();
diff --git a/gdb/testsuite/gdb.opt/inline-cmds.exp b/gdb/testsuite/gdb.opt/inline-cmds.exp
index d57a333..684f4dd 100644
--- a/gdb/testsuite/gdb.opt/inline-cmds.exp
+++ b/gdb/testsuite/gdb.opt/inline-cmds.exp
@@ -13,6 +13,9 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
 standard_testfile .c inline-markers.c
 
 if {[prepare_for_testing $testfile.exp $testfile \
@@ -315,3 +318,62 @@ gdb_test "up" "#3  .*outer_inline2.*" "up to outer_inline2"
 gdb_test "info frame" ".*inlined into frame.*" "outer_inline2 inlined"
 gdb_test "up" "#4  main.*" "up from outer_inline2"
 gdb_test "info frame" ".*\n caller of frame.*" "main not inlined"
+
+gdb_exit
+
+# Send a CLI "step" command over MI.  CLI_OUTPUT_RE is a regexp that
+# matches the expected CLI output.  MESSAGE is used as test message.
+
+proc mi_cli_step {cli_output_re message} {
+    global mi_gdb_prompt
+    global srcfile
+    global decimal
+
+    send_gdb "interpreter-exec console \"step\"\n"
+    gdb_expect {
+	-re "\\^running\r\n\\*running,thread-id=\"all\"\r\n${mi_gdb_prompt}${cli_output_re}" {
+	    pass $message
+	}
+	timeout {
+	    fail "$message (timeout)"
+	}
+	eof {
+	    fail "$message (eof)"
+	}
+    }
+
+    # mi_expect_stop handles "set mi-async on/off" differences.
+    mi_expect_stop "end-stepping-range" "\[^\r\n\]*" "" ".*$srcfile" "$decimal" \
+	"" "got *stopped for $message"
+}
+
+# Test that stepping into an inlined function with the CLI "step"
+# command run while the top interpreter is MI results in the expected
+# CLI output sent to MI's console.
+with_test_prefix "mi" {
+    if [mi_gdb_start] {
+	continue
+    }
+    mi_gdb_load ${binfile}
+    mi_runto main
+
+    set line_number [gdb_get_line_number "set mi break here"]
+    mi_gdb_test "-break-insert ${srcfile}:${line_number}" \
+	{\^done,bkpt=.number="2",type="breakpoint".*\}} \
+	"set breakpoint"
+
+    mi_execute_to "exec-continue" "breakpoint-hit" "main" "" ".*" ".*" \
+	{ "" "disp=\"keep\"" } "breakpoint hit"
+
+    incr line_number 2
+
+    # Step to the line that does an inline call.
+    set re "~\"$line_number\\\\t  result = func1 \\(\\);\\\\n\"\r\n"
+    mi_cli_step "${re}" "step to inline call"
+
+    # Step into the inlined function.
+    set re [multi_line \
+		"~\"func1 \\(\\) at .*$srcfile:$decimal\\\\n\"" \
+		"~\"$decimal\\\\t  bar \\(\\);\\\\n\"\r\n"]
+    mi_cli_step "${re}" "step into inline call"
+}
diff --git a/gdb/thread-fsm.c b/gdb/thread-fsm.c
index 52b4eb8..5ba4d56 100644
--- a/gdb/thread-fsm.c
+++ b/gdb/thread-fsm.c
@@ -22,8 +22,10 @@
 /* See thread-fsm.h.  */
 
 void
-thread_fsm_ctor (struct thread_fsm *self, struct thread_fsm_ops *ops)
+thread_fsm_ctor (struct thread_fsm *self, struct thread_fsm_ops *ops,
+		 struct interp *cmd_interp)
 {
+  self->command_interp = cmd_interp;
   self->finished = 0;
   self->ops = ops;
 }
@@ -44,18 +46,18 @@ thread_fsm_delete (struct thread_fsm *self)
 /* See thread-fsm.h.  */
 
 void
-thread_fsm_clean_up (struct thread_fsm *self)
+thread_fsm_clean_up (struct thread_fsm *self, struct thread_info *thread)
 {
   if (self->ops->clean_up != NULL)
-    self->ops->clean_up (self);
+    self->ops->clean_up (self, thread);
 }
 
 /* See thread-fsm.h.  */
 
 int
-thread_fsm_should_stop (struct thread_fsm *self)
+thread_fsm_should_stop (struct thread_fsm *self, struct thread_info *thread)
 {
-  return self->ops->should_stop (self);
+  return self->ops->should_stop (self, thread);
 }
 
 /* See thread-fsm.h.  */
diff --git a/gdb/thread-fsm.h b/gdb/thread-fsm.h
index b0f4c44..86fb81f 100644
--- a/gdb/thread-fsm.h
+++ b/gdb/thread-fsm.h
@@ -35,6 +35,14 @@ struct thread_fsm
 
   /* Whether the FSM is done successfully.  */
   int finished;
+
+  /* The interpreter that issued the execution command that caused
+     this thread to resume.  If the top level interpreter is MI/async,
+     and the execution command was a CLI command (next/step/etc.),
+     we'll want to print stop event output to the MI console channel
+     (the stepped-to line, etc.), as if the user entered the execution
+     command on a real GDB console.  */
+  struct interp *command_interp;
 };
 
 /* The virtual table of a thread_fsm.  */
@@ -49,7 +57,7 @@ struct thread_fsm_ops
   /* Called to clean up target resources after the FSM.  E.g., if the
      FSM created internal breakpoints, this is where they should be
      deleted.  */
-  void (*clean_up) (struct thread_fsm *self);
+  void (*clean_up) (struct thread_fsm *self, struct thread_info *thread);
 
   /* Called after handle_inferior_event decides the target is done
      (that is, after stop_waiting).  The FSM is given a chance to
@@ -58,7 +66,7 @@ struct thread_fsm_ops
      should be re-resumed.  This is a good place to cache target data
      too.  For example, the "finish" command saves the just-finished
      function's return value here.  */
-  int (*should_stop) (struct thread_fsm *self);
+  int (*should_stop) (struct thread_fsm *self, struct thread_info *thread);
 
   /* If this FSM saved a function's return value, you can use this
      method to retrieve it.  Otherwise, this returns NULL.  */
@@ -72,17 +80,20 @@ struct thread_fsm_ops
   int (*should_notify_stop) (struct thread_fsm *self);
 };
 /* Initialize FSM.  */
-extern void thread_fsm_ctor (struct thread_fsm *fsm,
-			     struct thread_fsm_ops *ops);
+extern void thread_fsm_ctor (struct thread_fsm *self,
+			     struct thread_fsm_ops *ops,
+			     struct interp *cmd_interp);
 
 /* Calls the FSM's dtor method, and then frees FSM.  */
 extern void thread_fsm_delete (struct thread_fsm *fsm);
 
 /* Calls the FSM's clean_up method.  */
-extern void thread_fsm_clean_up (struct thread_fsm *fsm);
+extern void thread_fsm_clean_up (struct thread_fsm *fsm,
+				 struct thread_info *thread);
 
 /* Calls the FSM's should_stop method.  */
-extern int thread_fsm_should_stop (struct thread_fsm *fsm);
+extern int thread_fsm_should_stop (struct thread_fsm *fsm,
+				   struct thread_info *thread);
 
 /* Calls the FSM's return_value method.  */
 extern struct return_value_info *
diff --git a/gdb/thread.c b/gdb/thread.c
index 75bfb47..91967e9 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -166,7 +166,7 @@ thread_cancel_execution_command (struct thread_info *thr)
 {
   if (thr->thread_fsm != NULL)
     {
-      thread_fsm_clean_up (thr->thread_fsm);
+      thread_fsm_clean_up (thr->thread_fsm, thr);
       thread_fsm_delete (thr->thread_fsm);
       thr->thread_fsm = NULL;
     }
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 00/34] Towards great frontend GDB consoles
@ 2016-05-06 12:35 Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 02/34] [Ada catchpoints] Fix "warning: failed to get exception name: No definition of \"e.full_name\" in current context" Pedro Alves
                   ` (35 more replies)
  0 siblings, 36 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

Here's an update of the series I last posted here:
  https://sourceware.org/ml/gdb-patches/2016-03/msg00388.html

New in v3:

 - Now at 34 patches, from 25.

 - ChangeLog entries

 - A lot of missing comments.

 - GDB manual / NEWS documentation bits written

 - Testing infrustruture add, plus new tests.
 
   This allowed testing on x64-64 Fedora 23 with all MI tests forced
   to run MI on a separate UI, which revealed a few problems, all
   addressed.

 - Many bugs fixed, as exposed by the testsuite.
 
 - Bugs reported by Marc Khozam fixed (interpreter-exec; repeat;
   console stuck with -exec-run and "set inferior-tty").
 
 - "info uis" command dropped for now.

Force-pushed to users/palves/console at sourceware.org.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Series intro:

This series provides a way to for frontends's GDB console to be on par
with gdb's native console running on a terminal.

The current support for implementing a GDB console that MI frontends
have available, based on "-interpreter-exec console", leaves readline,
history, completion, when to show/hide/print the prompt (sync vs async
execution), pagination, etc. all up to the frontend.

The end result is that all frontends have a real bad GDB console
experience, if they provide one at all.

GDB already has to handle all that for the native CLI, when GDB is
started without MI.  This series leverages that.  Instead, have
Eclipse create a pty and wrap it in a window widget -- the same as
Eclipse's shell console -- and start GDB in that pty.  Then, create a
second pty for MI communication, and tell GDB to start a MI
interpreter there, with a new "new-ui mi /dev/pts/N" command.

GDB then creates/manages a CLI on its terminal, with readline,
history, etc., support all done by GDB.

It's also possible to start extra CLI consoles, with "new-ui console
/dev/pts/N".  The current limitation is that these extra consoles
don't have readline active (work as if "set editing off"), because
there can only be one instance of readline in a process, currently.
(I have a readline patch that addresses it, but it'll need API and
implementation discussion and it may or not be accepted.)

It should be possible to start gdb in MI mode, and then start an extra
console, and support readline on that console (since there's still
just one readline user), though it'll need a little bit more work to
get there.  I just didn't try it yet, but it's definitely possible.

My original prototype did start out by doing things the other way
around -- start GDB in MI mode, and then start an extra CLI console on
a separate tty.  I handed over that (functional) prototype to Marc
Khouzam @ Eclipse CDT a while ago, and after experimentation and
discussion, we ended up concluding that starting GDB in CLI mode
instead was both easier and actually also makes it possible to support
an interesting use case -- connect an Eclipse frontend to a GDB that
is already running outside Eclipse.  Say, you're debugging on a
terminal, and then suddendly decide to start Eclipse's Standalone
Debugger _reusing_ your existing GDB, without having to start the
debug session from scratch.  Magic.

The current usage is "new-ui <interpreter> <tty>".

E.g., on a terminal run this scriplet:

 $ cat gdb-client
 #!/bin/bash

 reset
 tty
 tail -f /dev/null

 $ gdb-client
 /dev/pts/15

Now run gdb on another terminal, and tell it to start an MI
interpreter on the tty of the other terminal:

 ...
 (gdb) new-ui mi /dev/pts/15
 New UI allocated

Now back to the the gdb-client terminal, we'll get an MI prompt, ready
for MI input:

 /dev/pts/15
 =thread-group-added,id="i1"
 (gdb)

You can also start a new UI running a CLI, with:

 (gdb) new-ui console /dev/pts/15

More details in patch 29, which actually adds the new-ui command.

In case I messed up something on this update, you can still find v1 on
my github:
  https://github.com/palves/gdb/commits/palves/console-v2

Pedro Alves (34):
  Prepare gdb.python/mi-py-events.exp for Python/MI in separate channels
  [Ada catchpoints] Fix "warning: failed to get exception name: No
    definition of \"e.full_name\" in current context"
  Introduce "struct ui"
  Make gdb_stdout&co be per UI
  Make the interpreters be per UI
  Introduce interpreter factories
  Make the intepreters output to all UIs
  Always run async signal handlers in the main UI
  Make instream be per UI
  Make input_fd be per UI
  Make out and error streams be per UI
  Delete def_uiout
  Make current_ui_out be per UI
  Make command line editing (use of readline) be per UI
  Always process target events in the main UI
  Make target_terminal_inferior/ours almost nops on non-main UIs
  Introduce display_mi_prompt
  Make raw_stdout be per MI instance
  Simplify starting the command event loop
  Make gdb_in_secondary_prompt_p() be per UI
  Replace the sync_execution global with a new enum prompt_state
    tristate
  Fix for spurious prompts in secondary UIs
  New function should_print_stop_to_console
  Push thread->control.command_interp to the struct thread_fsm
  Only send sync execution command output to the UI that ran the command
  Make main_ui be heap allocated
  Handle UI's terminal closing
  Make stdin be per UI
  Add new command to create extra console/mi UI channels
  [DOC] Document support for running interpreters on separate UI
    channels
  Add testing infrastruture bits for running with MI on a separate UI
  Send deleted watchpoint-scope output to all UIs
  Make mi-break.exp always expect breakpoint commands output on the main
    UI
  Always switch fork child to the main UI

 gdb/doc/gdb.texinfo                          |   55 +-
 gdb/NEWS                                     |   16 +
 gdb/ada-lang.c                               |    9 +
 gdb/annotate.c                               |   15 +-
 gdb/breakpoint.c                             |   61 +-
 gdb/cli/cli-interp.c                         |  255 ++++--
 gdb/cli/cli-interp.h                         |   32 +
 gdb/cli/cli-script.c                         |   33 +-
 gdb/compile/compile.c                        |   14 +-
 gdb/defs.h                                   |    4 +-
 gdb/event-loop.c                             |    5 +
 gdb/event-top.c                              |  343 ++++----
 gdb/event-top.h                              |   13 +-
 gdb/exceptions.c                             |    4 +-
 gdb/fork-child.c                             |   22 +-
 gdb/gdbthread.h                              |    5 -
 gdb/guile/guile.c                            |   14 +-
 gdb/guile/scm-ports.c                        |    6 +-
 gdb/inf-loop.c                               |    2 +-
 gdb/infcall.c                                |   50 +-
 gdb/infcmd.c                                 |  104 +--
 gdb/inflow.c                                 |   35 -
 gdb/infrun.c                                 |  157 ++--
 gdb/infrun.h                                 |   15 +-
 gdb/interps.c                                |  288 +++++--
 gdb/interps.h                                |   67 +-
 gdb/linux-nat.c                              |    2 -
 gdb/main.c                                   |   53 +-
 gdb/mi/mi-cmds.h                             |    3 -
 gdb/mi/mi-common.h                           |    7 +
 gdb/mi/mi-interp.c                           | 1131 +++++++++++++++-----------
 gdb/mi/mi-main.c                             |   95 ++-
 gdb/mi/mi-main.h                             |    4 +-
 gdb/python/python.c                          |   15 +-
 gdb/remote.c                                 |    2 -
 gdb/target.c                                 |   40 +-
 gdb/testsuite/README                         |    6 +
 gdb/testsuite/gdb.ada/mi_catch_ex.exp        |   41 +-
 gdb/testsuite/gdb.gdb/selftest.exp           |    4 +
 gdb/testsuite/gdb.mi/mi-break.exp            |   69 +-
 gdb/testsuite/gdb.mi/mi-editing.exp          |   37 +
 gdb/testsuite/gdb.mi/mi-exec-run.exp         |  158 ++++
 gdb/testsuite/gdb.mi/mi-watch.exp            |   85 +-
 gdb/testsuite/gdb.opt/inline-cmds.c          |    2 +-
 gdb/testsuite/gdb.opt/inline-cmds.exp        |   62 ++
 gdb/testsuite/gdb.python/py-mi-events-gdb.py |   12 +-
 gdb/testsuite/gdb.python/py-mi-events.exp    |   21 +-
 gdb/testsuite/lib/gdb.exp                    |    3 +-
 gdb/testsuite/lib/mi-support.exp             |  159 +++-
 gdb/thread-fsm.c                             |   12 +-
 gdb/thread-fsm.h                             |   23 +-
 gdb/thread.c                                 |    2 +-
 gdb/top.c                                    |  367 +++++++--
 gdb/top.h                                    |  174 +++-
 gdb/tui/tui-interp.c                         |  175 +++-
 gdb/tui/tui-io.c                             |    6 +-
 gdb/tui/tui.c                                |    2 +-
 gdb/ui-file.c                                |    4 +-
 gdb/ui-file.h                                |    4 +-
 gdb/ui-out.c                                 |  184 -----
 gdb/ui-out.h                                 |    3 +-
 gdb/utils.c                                  |    7 +-
 gdb/utils.h                                  |   19 +-
 63 files changed, 3090 insertions(+), 1527 deletions(-)
 create mode 100644 gdb/cli/cli-interp.h
 create mode 100644 gdb/testsuite/gdb.mi/mi-editing.exp
 create mode 100644 gdb/testsuite/gdb.mi/mi-exec-run.exp

-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 20/34] Make gdb_in_secondary_prompt_p() be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (3 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 29/34] Add new command to create extra console/mi UI channels Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 33/34] Make mi-break.exp always expect breakpoint commands output on the main UI Pedro Alves
                   ` (30 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* top.c (gdb_secondary_prompt_depth): Delete.
	(gdb_in_secondary_prompt_p): Add ui parameter.  Use it.
	(gdb_readline_wrapper_cleanup, gdb_readline_wrapper): Adjust to
	per-UI gdb_secondary_prompt_depth.
	* top.h (struct ui) <secondary_prompt_depth>: New field.
---
 gdb/top.c        | 15 +++++----------
 gdb/top.h        |  9 +++++++--
 gdb/tui/tui-io.c |  4 ++--
 gdb/tui/tui.c    |  2 +-
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/gdb/top.c b/gdb/top.c
index 7e82dcf..79f4293 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -757,17 +757,12 @@ static char *gdb_readline_wrapper_result;
 static void (*saved_after_char_processing_hook) (void);
 
 
-/* The number of nested readline secondary prompts that are currently
-   active.  */
-
-static int gdb_secondary_prompt_depth = 0;
-
 /* See top.h.  */
 
 int
-gdb_in_secondary_prompt_p (void)
+gdb_in_secondary_prompt_p (struct ui *ui)
 {
-  return gdb_secondary_prompt_depth > 0;
+  return ui->secondary_prompt_depth > 0;
 }
 
 
@@ -828,8 +823,8 @@ gdb_readline_wrapper_cleanup (void *arg)
 
   gdb_readline_wrapper_result = NULL;
   gdb_readline_wrapper_done = 0;
-  gdb_secondary_prompt_depth--;
-  gdb_assert (gdb_secondary_prompt_depth >= 0);
+  ui->secondary_prompt_depth--;
+  gdb_assert (ui->secondary_prompt_depth >= 0);
 
   after_char_processing_hook = saved_after_char_processing_hook;
   saved_after_char_processing_hook = NULL;
@@ -859,7 +854,7 @@ gdb_readline_wrapper (const char *prompt)
 
   cleanup->target_is_async_orig = target_is_async_p ();
 
-  gdb_secondary_prompt_depth++;
+  ui->secondary_prompt_depth++;
   back_to = make_cleanup (gdb_readline_wrapper_cleanup, cleanup);
 
   if (cleanup->target_is_async_orig)
diff --git a/gdb/top.h b/gdb/top.h
index 3447a2f..efe97b1 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -73,6 +73,10 @@ struct ui
      "start" -ex "next"') are processed.  */
   int async;
 
+  /* The number of nested readline secondary prompts that are
+     currently active.  */
+  int secondary_prompt_depth;
+
   /* stdio stream that command input is being read from.  Set to stdin
      normally.  Set by source_command to the file we are sourcing.
      Set to NULL if we are executing a user-defined command or
@@ -190,9 +194,10 @@ extern char *get_prompt (void);
    by gdb for its command prompt.  */
 extern void set_prompt (const char *s);
 
-/* Return 1 if the current input handler is a secondary prompt, 0 otherwise.  */
+/* Return 1 if UI's current input handler is a secondary prompt, 0
+   otherwise.  */
 
-extern int gdb_in_secondary_prompt_p (void);
+extern int gdb_in_secondary_prompt_p (struct ui *ui);
 
 /* From random places.  */
 extern int readnow_symbol_files;
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 6f2d892..ed79b44 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -212,7 +212,7 @@ tui_redisplay_readline (void)
      The command could call prompt_for_continue and we must not
      restore SingleKey so that the prompt and normal keymap are used.  */
   if (tui_current_key_mode == TUI_ONE_COMMAND_MODE && rl_end == 0
-      && !gdb_in_secondary_prompt_p ())
+      && !gdb_in_secondary_prompt_p (current_ui))
     tui_set_key_mode (TUI_SINGLE_KEY_MODE);
 
   if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
@@ -585,7 +585,7 @@ tui_getc (FILE *fp)
          with empty lines with gdb prompt at beginning.  Instead of that,
          stay on the same line but provide a visual effect to show the
          user we recognized the command.  */
-      if (rl_end == 0 && !gdb_in_secondary_prompt_p ())
+      if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
         {
 	  wmove (w, getcury (w), 0);
 
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index 96f8df7..d67cfd9 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -304,7 +304,7 @@ tui_rl_startup_hook (void)
 {
   rl_already_prompted = 1;
   if (tui_current_key_mode != TUI_COMMAND_MODE
-      && !gdb_in_secondary_prompt_p ())
+      && !gdb_in_secondary_prompt_p (current_ui))
     tui_set_key_mode (TUI_SINGLE_KEY_MODE);
   tui_redisplay_readline ();
   return 0;
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 03/34] Introduce "struct ui"
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 02/34] [Ada catchpoints] Fix "warning: failed to get exception name: No definition of \"e.full_name\" in current context" Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 29/34] Add new command to create extra console/mi UI channels Pedro Alves
                   ` (32 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

This is a step towards supporting multiple consoles/MIs, each on its
own stdio streams / terminal.

See intro comment in top.h.

(I've had trouble picking a name for this object.  I've started out
with "struct console" originally.  But then this is about MI as well,
and there's "interpreter-exec console", which is specifically about
the CLI...

So I changed to "struct terminal", but, then we have a terminal object
that works when the input is not a terminal as well ...

Then I sort of gave up and renamed it to "struct top_level".  But it
then gets horribly confusing when we talk about the "top level
interpreter that's running on the current top level".

In the end, I realized we're already sort of calling this "ui", in
struct ui_out, struct ui_file, and a few coments here and there.)

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-top.c: Update readline-related comments.
	(input_handler, call_readline): Delete globals.
	(gdb_rl_callback_handler): Call the current UI's input_handler
	method.
	(change_line_handler): Adjust to set current UI's properties
	instead of globals.
	(current_ui_, current_ui): New globals.
	(get_command_line_buffer): Rewrite to refer to the current UI.
	(stdin_event_handler): Adjust to call the call_readline method of
	the current UI.
	(gdb_readline_no_editing_callback): Adjust to call the current UI's
	input_handler method.
	(gdb_setup_readline): Adjust to set current UI's properties
	instead of globals.
	* event-top.h (call_readline, input_handler): Delete declarations.
	* mi/mi-interp.c (mi_interpreter_resume): Adjust to set current
	UI's properties instead of globals.
	* top.c (gdb_readline_wrapper_cleanup): Adjust to set current UI's
	properties instead of globals.
	(gdb_readline_wrapper): Adjust to call and set current UI's
	methods instead of globals.
	* top.h: Include buffer.h and event-loop.h.
	(struct ui): New struct.
	(current_ui): New declaration.
---
 gdb/event-top.c    | 74 +++++++++++++++++++++---------------------------------
 gdb/event-top.h    |  2 --
 gdb/mi/mi-interp.c |  5 ++--
 gdb/top.c          | 10 +++++---
 gdb/top.h          | 33 +++++++++++++++++++++++-
 5 files changed, 70 insertions(+), 54 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index f43fd0a..664543c 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -75,28 +75,10 @@ static void async_stop_sig (gdb_client_data);
 #endif
 static void async_sigterm_handler (gdb_client_data arg);
 
-/* Readline offers an alternate interface, via callback
-   functions.  These are all included in the file callback.c in the
-   readline distribution.  This file provides (mainly) a function, which
-   the event loop uses as callback (i.e. event handler) whenever an event
-   is detected on the standard input file descriptor.
-   readline_callback_read_char is called (by the GDB event loop) whenever
-   there is a new character ready on the input stream.  This function
-   incrementally builds a buffer internal to readline where it
-   accumulates the line read up to the point of invocation.  In the
-   special case in which the character read is newline, the function
-   invokes a GDB supplied callback routine, which does the processing of
-   a full command line.  This latter routine is the asynchronous analog
-   of the old command_line_input in gdb.  Instead of invoking (and waiting
-   for) readline to read the command line and pass it back to
-   command_loop for processing, the new command_line_handler function has
-   the command line already available as its parameter.  INPUT_HANDLER is
-   to be set to the function that readline will invoke when a complete
-   line of input is ready.  CALL_READLINE is to be set to the function
-   that readline offers as callback to the event_loop.  */
-
-void (*input_handler) (char *);
-void (*call_readline) (gdb_client_data);
+/* Instead of invoking (and waiting for) readline to read the command
+   line and pass it back for processing, we use readline's alternate
+   interface, via callback functions, so that the event loop can react
+   to other event sources while we wait for input.  */
 
 /* Important variables for the event loop.  */
 
@@ -217,10 +199,11 @@ static void
 gdb_rl_callback_handler (char *rl)
 {
   struct gdb_exception gdb_rl_expt = exception_none;
+  struct ui *ui = current_ui;
 
   TRY
     {
-      input_handler (rl);
+      ui->input_handler (rl);
     }
   CATCH (ex, RETURN_MASK_ALL)
     {
@@ -261,6 +244,8 @@ cli_command_loop (void *data)
 static void
 change_line_handler (void)
 {
+  struct ui *ui = current_ui;
+
   /* NOTE: this operates on input_fd, not instream.  If we are reading
      commands from a file, instream will point to the file.  However in
      async mode, we always read commands from a file with editing
@@ -270,18 +255,18 @@ change_line_handler (void)
   if (async_command_editing_p)
     {
       /* Turn on editing by using readline.  */
-      call_readline = gdb_rl_callback_read_char_wrapper;
-      input_handler = command_line_handler;
+      ui->call_readline = gdb_rl_callback_read_char_wrapper;
+      ui->input_handler = command_line_handler;
     }
   else
     {
       /* Turn off editing by using gdb_readline_no_editing_callback.  */
       gdb_rl_callback_handler_remove ();
-      call_readline = gdb_readline_no_editing_callback;
+      ui->call_readline = gdb_readline_no_editing_callback;
 
       /* Set up the command handler as well, in case we are called as
          first thing from .gdbinit.  */
-      input_handler = command_line_handler;
+      ui->input_handler = command_line_handler;
     }
 }
 
@@ -452,22 +437,16 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-/* Get a pointer to the command line buffer.  This is used to
+static struct ui current_ui_;
+struct ui *current_ui = &current_ui_;
+
+/* Get a pointer to the current UI's line buffer.  This is used to
    construct a whole line of input from partial input.  */
 
 static struct buffer *
 get_command_line_buffer (void)
 {
-  static struct buffer line_buffer;
-  static int line_buffer_initialized;
-
-  if (!line_buffer_initialized)
-    {
-      buffer_init (&line_buffer);
-      line_buffer_initialized = 1;
-    }
-
-  return &line_buffer;
+  return &current_ui->line_buffer;
 }
 
 /* When there is an event ready on the stdin file descriptor, instead
@@ -478,6 +457,8 @@ get_command_line_buffer (void)
 void
 stdin_event_handler (int error, gdb_client_data client_data)
 {
+  struct ui *ui = current_ui;
+
   if (error)
     {
       printf_unfiltered (_("error detected on stdin\n"));
@@ -499,7 +480,7 @@ stdin_event_handler (int error, gdb_client_data client_data)
       do
 	{
 	  call_stdin_event_handler_again_p = 0;
-	  (*call_readline) (client_data);
+	  ui->call_readline (client_data);
 	} while (call_stdin_event_handler_again_p != 0);
     }
 }
@@ -756,6 +737,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
   char *result;
   struct buffer line_buffer;
   static int done_once = 0;
+  struct ui *ui = current_ui;
 
   buffer_init (&line_buffer);
 
@@ -795,7 +777,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
 	      break;
 	    }
 	  xfree (buffer_finish (&line_buffer));
-	  (*input_handler) (0);
+	  ui->input_handler (NULL);
 	  return;
 	}
 
@@ -812,7 +794,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
 
   buffer_grow_char (&line_buffer, '\0');
   result = buffer_finish (&line_buffer);
-  (*input_handler) (result);
+  ui->input_handler (result);
 }
 \f
 
@@ -1198,6 +1180,8 @@ set_async_editing_command (char *args, int from_tty,
 void
 gdb_setup_readline (void)
 {
+  struct ui *ui = current_ui;
+
   /* This function is a noop for the sync case.  The assumption is
      that the sync setup is ALL done in gdb_init, and we would only
      mess it up here.  The sync stuff should really go away over
@@ -1220,19 +1204,19 @@ gdb_setup_readline (void)
 	  
       /* When a character is detected on instream by select or poll,
 	 readline will be invoked via this callback function.  */
-      call_readline = gdb_rl_callback_read_char_wrapper;
+      ui->call_readline = gdb_rl_callback_read_char_wrapper;
     }
   else
     {
       async_command_editing_p = 0;
-      call_readline = gdb_readline_no_editing_callback;
+      ui->call_readline = gdb_readline_no_editing_callback;
     }
   
   /* When readline has read an end-of-line character, it passes the
      complete line to gdb for processing; command_line_handler is the
      function that does this.  */
-  input_handler = command_line_handler;
-      
+  ui->input_handler = command_line_handler;
+
   /* Tell readline to use the same input stream that gdb uses.  */
   rl_instream = instream;
 
diff --git a/gdb/event-top.h b/gdb/event-top.h
index bef2530..04956a5 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -57,8 +57,6 @@ extern void async_enable_stdin (void);
 extern int async_command_editing_p;
 extern int exec_done_display_p;
 extern struct prompts the_prompts;
-extern void (*call_readline) (void *);
-extern void (*input_handler) (char *);
 extern int input_fd;
 extern void (*after_char_processing_hook) (void);
 extern int call_stdin_event_handler_again_p;
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index b37dc96..7c82950 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -174,6 +174,7 @@ static int
 mi_interpreter_resume (void *data)
 {
   struct mi_interp *mi = (struct mi_interp *) data;
+  struct ui *ui = current_ui;
 
   /* As per hack note in mi_interpreter_init, swap in the output
      channels... */
@@ -181,8 +182,8 @@ mi_interpreter_resume (void *data)
 
   /* These overwrite some of the initialization done in
      _intialize_event_loop.  */
-  call_readline = gdb_readline_no_editing_callback;
-  input_handler = mi_execute_command_input_handler;
+  ui->call_readline = gdb_readline_no_editing_callback;
+  ui->input_handler = mi_execute_command_input_handler;
   async_command_editing_p = 0;
   /* 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
diff --git a/gdb/top.c b/gdb/top.c
index f5ef718..cae90d6 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -794,13 +794,14 @@ struct gdb_readline_wrapper_cleanup
 static void
 gdb_readline_wrapper_cleanup (void *arg)
 {
+  struct ui *ui = current_ui;
   struct gdb_readline_wrapper_cleanup *cleanup
     = (struct gdb_readline_wrapper_cleanup *) arg;
 
   rl_already_prompted = cleanup->already_prompted_orig;
 
-  gdb_assert (input_handler == gdb_readline_wrapper_line);
-  input_handler = cleanup->handler_orig;
+  gdb_assert (ui->input_handler == gdb_readline_wrapper_line);
+  ui->input_handler = cleanup->handler_orig;
 
   /* Don't restore our input handler in readline yet.  That would make
      readline prep the terminal (putting it in raw mode), while the
@@ -826,13 +827,14 @@ gdb_readline_wrapper_cleanup (void *arg)
 char *
 gdb_readline_wrapper (const char *prompt)
 {
+  struct ui *ui = current_ui;
   struct cleanup *back_to;
   struct gdb_readline_wrapper_cleanup *cleanup;
   char *retval;
 
   cleanup = XNEW (struct gdb_readline_wrapper_cleanup);
-  cleanup->handler_orig = input_handler;
-  input_handler = gdb_readline_wrapper_line;
+  cleanup->handler_orig = ui->input_handler;
+  ui->input_handler = gdb_readline_wrapper_line;
 
   cleanup->already_prompted_orig = rl_already_prompted;
 
diff --git a/gdb/top.h b/gdb/top.h
index a498f39..fc4e90a 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -20,7 +20,38 @@
 #ifndef TOP_H
 #define TOP_H
 
-struct buffer;
+#include "buffer.h"
+#include "event-loop.h"
+
+/* 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
+   with -i on the command line) and secondary interpreters (for
+   interpreter-exec ...), etc.  There's always one UI associated with
+   stdin/stdout/stderr, but the user can create secondary UIs, for
+   example, to create a separate MI channel on its own stdio
+   streams.  */
+
+struct ui
+{
+  /* The UI's command line buffer.  This is to used to accumulate
+     input until we have a whole command line.  */
+  struct buffer line_buffer;
+
+  /* The callback used by the event loop whenever an event is detected
+     on the UI's input file descriptor.  This function incrementally
+     builds a buffer where it accumulates the line read up to the
+     point of invocation.  In the special case in which the character
+     read is newline, the function invokes the INPUT_HANDLER callback
+     (see below).  */
+  void (*call_readline) (gdb_client_data);
+
+  /* The function to invoke when a complete line of input is ready for
+     processing.  */
+  void (*input_handler) (char *);
+};
+
+extern struct ui *current_ui;
 
 /* From top.c.  */
 extern char *saved_command_line;
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 21/34] Replace the sync_execution global with a new enum prompt_state tristate
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (7 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 15/34] Always process target events in the main UI Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 16/34] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
                   ` (26 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

When sync_execution (a boolean) is true, it means we're running a
foreground command -- we hide the prompt stop listening to input, give
the inferior the terminal, then go to the event loop waiting for the
target to stop.

With multiple independent UIs, we need to track whether each UI is
synchronously blocked waiting for the target.  IOW, if you do
"continue" in one console, that console stops accepting commands, but
you should still be free to type other commands in the others
consoles.

Just simply making sync_execution be per-UI alone not sufficient,
because of this in fetch_inferior_event:

  /* 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 ();

We'd have to record at entry the "was_sync" state for each UI, not
just of the current UI.

This patch instead replaces the sync_execution flag by a per-UI
tristate flag indicating the command line 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,
 ;

I think the end result is _much_ clearer than the current code, and,
it addresses the original motivation too.

gdb/ChangeLog:
2016-05-01  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.
---
 gdb/annotate.c     |  15 ++-----
 gdb/event-loop.c   |   1 +
 gdb/event-top.c    |  29 +++++++++-----
 gdb/infcall.c      |  34 +++++++++++-----
 gdb/infcmd.c       |  28 +++++++++----
 gdb/infrun.c       | 114 +++++++++++++++++++++++++++++++++++++----------------
 gdb/infrun.h       |  10 ++---
 gdb/main.c         |  11 ++++--
 gdb/mi/mi-interp.c |  25 ++++++------
 gdb/target.c       |   6 +--
 gdb/top.c          |   8 ++--
 gdb/top.h          |  25 ++++++++++++
 12 files changed, 204 insertions(+), 102 deletions(-)

diff --git a/gdb/annotate.c b/gdb/annotate.c
index 117f122..64175a4 100644
--- a/gdb/annotate.c
+++ b/gdb/annotate.c
@@ -25,6 +25,7 @@
 #include "observer.h"
 #include "inferior.h"
 #include "infrun.h"
+#include "top.h"
 \f
 
 /* 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.  */
diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index fe28305..f94a6fa 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -381,6 +381,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,
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 5e42c56..c9e7548 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -354,7 +354,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
@@ -377,10 +381,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
@@ -541,14 +546,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;
     }
 }
 
@@ -558,7 +561,9 @@ async_enable_stdin (void)
 void
 async_disable_stdin (void)
 {
-  sync_execution = 1;
+  struct ui *ui = current_ui;
+
+  ui->prompt_state = PROMPT_BLOCKED;
 }
 \f
 
@@ -774,8 +779,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);
     }
 }
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 11f5aba..d491f95 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -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;
 }
 
@@ -511,6 +518,8 @@ call_thread_fsm_should_stop (struct thread_fsm *self)
 
   if (stop_stack_dummy == STOP_STACK_DUMMY)
     {
+      struct cleanup *old_chain;
+
       /* Done.  */
       thread_fsm_set_finished (self);
 
@@ -520,7 +529,13 @@ 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 ();
+      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;
@@ -558,12 +573,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 +611,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 +1135,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);
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index a80b4c6..813d11a 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -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 (&current_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 (&current_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 ();
     }
 }
 
@@ -2691,8 +2705,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
@@ -2866,7 +2878,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;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2b4d331..b9b32c9 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -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
@@ -3806,7 +3802,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,
@@ -3816,7 +3814,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 ();
 }
 
@@ -3849,6 +3847,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.  */
 
@@ -3876,7 +3904,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;
@@ -3996,14 +4023,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)))
@@ -4690,17 +4715,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
@@ -8202,6 +8242,7 @@ normal_stop (void)
   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);
 
@@ -8266,19 +8307,24 @@ normal_stop (void)
       && 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.  */
@@ -8290,8 +8336,10 @@ normal_stop (void)
   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);
diff --git a/gdb/infrun.h b/gdb/infrun.h
index e79bf2d..01eff9a 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -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.  */
@@ -238,4 +233,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 */
diff --git a/gdb/main.c b/gdb/main.c
index 0bf52a9..541a077 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -315,8 +315,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 ();
@@ -368,7 +369,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);
 
@@ -395,7 +396,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);
 
@@ -519,6 +520,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.  */
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 240ab8d..0b12a66 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -92,8 +92,11 @@ static int report_initial_inferior (struct inferior *inf, void *closure);
 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
@@ -168,13 +171,6 @@ mi_interpreter_resume (void *data)
 
   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.  */
@@ -314,6 +310,9 @@ static void
 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);
 
@@ -322,7 +321,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 (mi);
 }
 
@@ -1115,12 +1114,10 @@ mi_on_resume_1 (struct mi_interp *mi, 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", mi->raw_stdout);
     }
   gdb_flush (mi->raw_stdout);
diff --git a/gdb/target.c b/gdb/target.c
index 12d5de2..6eddd88 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -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;
 
   /* Always delete the current UI's input file handler, regardless of
diff --git a/gdb/top.c b/gdb/top.c
index 79f4293..e40835b 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -391,7 +391,7 @@ void
 wait_sync_command_done (void)
 {
   while (gdb_do_one_event () >= 0)
-    if (!sync_execution)
+    if (current_ui->prompt_state != PROMPT_BLOCKED)
       break;
 }
 
@@ -404,7 +404,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 ();
 }
 
@@ -441,7 +443,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;
 
diff --git a/gdb/top.h b/gdb/top.h
index efe97b1..092cc26 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -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
@@ -91,6 +109,9 @@ struct ui
      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.  */
@@ -145,6 +166,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)		\
+
 /* Cleanup that restores the current UI.  */
 extern void restore_ui_cleanup (void *data);
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 15/34] Always process target events in the main UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (6 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 14/34] Make command line editing (use of readline) be per UI Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 21/34] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
                   ` (27 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

This makes target events always be always processed with the main UI
as current UI.  This way, warnings, debug output, etc. are always
consistently sent to the main console.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-top.c (restore_ui_cleanup): Make extern.
	* infrun.c (fetch_inferior_event): Always switch to the main UI.
	* top.h (restore_ui_cleanup): Declare.
---
 gdb/event-top.c | 4 ++--
 gdb/infrun.c    | 6 ++++++
 gdb/top.h       | 3 +++
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index c84b3f4..e90d00d 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -456,9 +456,9 @@ struct ui *main_ui = &main_ui_;
 struct ui *current_ui = &main_ui_;
 struct ui *ui_list = &main_ui_;
 
-/* Cleanup that restores the current UI.  */
+/* See top.h.  */
 
-static void
+void
 restore_ui_cleanup (void *data)
 {
   current_ui = (struct ui *) data;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index eb2388b..2b4d331 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3883,6 +3883,12 @@ fetch_inferior_event (void *client_data)
 
   memset (ecs, 0, sizeof (*ecs));
 
+  /* Events are always processed with the main UI as current UI.  This
+     way, warnings, debug output, etc. are always consistently sent to
+     the main console.  */
+  make_cleanup (restore_ui_cleanup, current_ui);
+  current_ui = main_ui;
+
   /* End up with readline processing input, if necessary.  */
   make_cleanup (reinstall_readline_callback_handler_cleanup, NULL);
 
diff --git a/gdb/top.h b/gdb/top.h
index 2facd1e..3447a2f 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -141,6 +141,9 @@ 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))		\
 
+/* Cleanup that restores the current UI.  */
+extern void restore_ui_cleanup (void *data);
+
 /* From top.c.  */
 extern char *saved_command_line;
 extern int in_user_command;
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 33/34] Make mi-break.exp always expect breakpoint commands output on the main UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (4 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 20/34] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 14/34] Make command line editing (use of readline) be per UI Pedro Alves
                   ` (29 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

mi-break.exp regresses when tested with MI running on a secondary UI,
with RUNTESTFLAGS="FORCE_SEPARATE_MI_TTY=1".

The problem is simply that the test sets a breakpoint, and attaches
"print" commands to the breakpoint.  Since breakpoint commands always
run with the main UI as current UI, the breakpoint command's output
goes to the main UI.  So we need to tweak the test to expect it there.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.mi/mi-break.exp (test_breakpoint_commands): Always expect
	breakpoint command's output on the main UI.
	(test_break): New procedure, factored out from calls in the top
	level.
	(top level): Use foreach_with_prefix to test MI as main UI and as
	separate UI.
---
 gdb/testsuite/gdb.mi/mi-break.exp | 69 +++++++++++++++++++++++++++------------
 1 file changed, 48 insertions(+), 21 deletions(-)

diff --git a/gdb/testsuite/gdb.mi/mi-break.exp b/gdb/testsuite/gdb.mi/mi-break.exp
index 85f328d..00293d7 100644
--- a/gdb/testsuite/gdb.mi/mi-break.exp
+++ b/gdb/testsuite/gdb.mi/mi-break.exp
@@ -23,11 +23,6 @@
 load_lib mi-support.exp
 set MIFLAGS "-i=mi"
 
-gdb_exit
-if [mi_gdb_start] {
-    continue
-}
-
 standard_testfile basics.c
 
 if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
@@ -35,10 +30,6 @@ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb
      return -1
 }
 
-mi_delete_breakpoints
-mi_gdb_reinitialize_dir $srcdir/$subdir
-mi_gdb_load ${binfile}
-
 # Locate line numbers in basics.c.
 set line_callee4_head  [gdb_get_line_number "callee4 ("]
 set line_callee4_body  [expr $line_callee4_head + 2]
@@ -292,9 +283,25 @@ proc test_breakpoint_commands {} {
 
     mi_send_resuming_command "exec-continue" "breakpoint commands: continue"
 
-    set test "intermediate stop and continue"
+
+    # The breakpoint command's output is always sent to the main UI,
+    # even when testing with MI running on a secondary UI.
+    global gdb_main_spawn_id
+
+    set test "intermediate stop and continue, bp commands"
     gdb_expect {
-        -re ".*\\\$1 = 0.*\\\$10 = 9.*\\*running" {
+	-i $gdb_main_spawn_id
+	-re ".*\\\$1 = 0.*\\\$10 = 9" {
+	    pass $test
+	}
+	timeout {
+	    fail $test
+	}
+    }
+
+    set test "intermediate stop and continue, mi running"
+    gdb_expect {
+        -re "\\*running" {
 	    pass $test
 	}
         timeout {
@@ -385,20 +392,40 @@ proc test_explicit_breakpoints {} {
 	".*Source filename requires function, label, or line offset.*"
 }
 
-test_tbreak_creation_and_listing
-test_rbreak_creation_and_listing
+proc test_break {mi_mode} {
+    global srcdir subdir binfile
+
+    mi_gdb_exit
+
+    if {$mi_mode == "separate"} {
+	set start_ops "separate-mi-tty"
+    } else {
+	set start_ops ""
+    }
+    if [mi_gdb_start $start_ops] {
+	return
+    }
+
+    mi_delete_breakpoints
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_load ${binfile}
 
-test_ignore_count
+    test_tbreak_creation_and_listing
+    test_rbreak_creation_and_listing
 
-test_error
+    test_ignore_count
 
-test_disabled_creation
+    test_error
 
-test_breakpoint_commands
+    test_disabled_creation
 
-test_abreak_creation
+    test_breakpoint_commands
 
-test_explicit_breakpoints
+    test_abreak_creation
 
-mi_gdb_exit
-return 0
+    test_explicit_breakpoints
+}
+
+foreach_with_prefix mi-mode {"main" "separate"} {
+    test_break ${mi-mode}
+}
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 16/34] Make target_terminal_inferior/ours almost nops on non-main UIs
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (8 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 21/34] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
@ 2016-05-06 12:35 ` Pedro Alves
  2016-05-06 12:35 ` [PATCH v3 01/34] Prepare gdb.python/mi-py-events.exp for Python/MI in separate channels Pedro Alves
                   ` (25 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:35 UTC (permalink / raw)
  To: gdb-patches

Since we always run the inferior in the main console (unless "set
inferior-tty" is in effect), when some UI other than the main one
calls target_terminal_inferior/target_terminal_inferior, then we only
register/unregister the UI's input from the event loop, but leave the
main UI's terminal settings as is.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* target.c (target_terminal_inferior): Bail out after
	unregistering input_fd if not on the main UI.
	(target_terminal_ours): Bail out after registering input_fd if not
	on the main UI.
	(target_terminal_ours_for_output): Bail out if not on the main UI.
---
 gdb/target.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/gdb/target.c b/gdb/target.c
index 2d16c96..12d5de2 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -493,6 +493,14 @@ target_terminal_inferior (void)
      UI.  */
   delete_file_handler (ui->input_fd);
 
+  /* Since we always run the inferior in the main console (unless "set
+     inferior-tty" is in effect), when some UI other than the main one
+     calls target_terminal_inferior/target_terminal_inferior, then we
+     only register/unregister the UI's input from the event loop, but
+     leave the main UI's terminal settings as is.  */
+  if (ui != main_ui)
+    return;
+
   if (terminal_state == terminal_is_inferior)
     return;
 
@@ -519,6 +527,10 @@ target_terminal_ours (void)
      UI.  */
   add_file_handler (ui->input_fd, stdin_event_handler, ui);
 
+  /* See target_terminal_inferior.  */
+  if (ui != main_ui)
+    return;
+
   if (terminal_state == terminal_is_ours)
     return;
 
@@ -531,6 +543,12 @@ target_terminal_ours (void)
 void
 target_terminal_ours_for_output (void)
 {
+  struct ui *ui = current_ui;
+
+  /* See target_terminal_inferior.  */
+  if (ui != main_ui)
+    return;
+
   if (terminal_state != terminal_is_inferior)
     return;
   (*current_target.to_terminal_ours_for_output) (&current_target);
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (10 preceding siblings ...)
  2016-05-06 12:35 ` [PATCH v3 01/34] Prepare gdb.python/mi-py-events.exp for Python/MI in separate channels Pedro Alves
@ 2016-05-06 12:36 ` Pedro Alves
  2016-06-28 20:19   ` Simon Marchi
  2016-05-06 12:40 ` [PATCH v3 13/34] Make current_ui_out be per UI Pedro Alves
                   ` (23 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:36 UTC (permalink / raw)
  To: gdb-patches

With this, a specific test may can start GDB with MI on a separate UI
by using:

  mi_gdb_start separate-mi-tty

In addition, it's also possible to run the whole testsuite with MI on
a separate tty, with:

 make check RUNTESTFLAGS="FORCE_SEPARATE_MI_TTY=1"

gdb_main_spawn_id and mi_spawn_id are added so that tests may expect
output from either channel.

While at it, inferior_spawn_id was not being cleared when gdb exits,
unlike the other spawn ids, thus a test that starts gdb more than once
would end up using a stale spawn id.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* README (Testsuite Parameters): Document FORCE_SEPARATE_MI_TTY.
	* lib/gdb.exp (default_gdb_exit): Clear inferior_spawn_id.
	* lib/mi-support.exp (mi_uncatched_gdb_exit): Unset
	gdb_main_spawn_id, mi_spawn_id, unset inferior_spawn_id.
	(gdb_main_spawn_id, mi_spawn_id): Declare and
	comment.
	(mi_create_inferior_pty): New procedure,
	factored out from default_mi_gdb_start.
	(switch_gdb_spawn_id, mi_gdb_start_separate_mi_tty): New
	procedures.
	(default_mi_gdb_start): Call mi_gdb_start_separate_mi_tty if the
	separate-mi-tty option is specified, or SEPARATE_MI_TTY is set.
	Use mi_create_inferior_pty.
	(mi_gdb_start): Use eval to pass down args list.
---
 gdb/testsuite/README             |   6 ++
 gdb/testsuite/lib/gdb.exp        |   3 +-
 gdb/testsuite/lib/mi-support.exp | 159 ++++++++++++++++++++++++++++++++-------
 3 files changed, 139 insertions(+), 29 deletions(-)

diff --git a/gdb/testsuite/README b/gdb/testsuite/README
index 043a8bd..152318a 100644
--- a/gdb/testsuite/README
+++ b/gdb/testsuite/README
@@ -208,6 +208,12 @@ FORCE_PARALLEL
 Setting FORCE_PARALLEL to any non-empty value forces parallel testing
 mode even if RUNTESTFLAGS is not empty.
 
+FORCE_SEPARATE_MI_TTY
+
+Setting FORCE_MI_SEPARATE_UI to 1 forces all MI testing to start GDB
+in console mode, with MI running on a separate TTY, on a secondary UI
+started with "new-ui".
+
 GDB_INOTIFY
 
 For debugging parallel mode, it is handy to be able to see when a test
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 6d25b0c..a374370 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -1359,7 +1359,7 @@ proc default_gdb_exit {} {
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
     global verbose
-    global gdb_spawn_id
+    global gdb_spawn_id inferior_spawn_id
     global inotify_log_file
 
     gdb_stop_suppressing_tests
@@ -1400,6 +1400,7 @@ proc default_gdb_exit {} {
 	remote_close host
     }
     unset gdb_spawn_id
+    unset inferior_spawn_id
 }
 
 # Load a file into the debugger.
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 87ce634..4c4a71a 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -28,6 +28,16 @@ if ![info exists mi_gdb_prompt] then {
 
 global mi_inferior_tty_name
 
+# Always points to GDB's main UI spawn ID, even when testing with MI
+# running on a secondary UI.
+global gdb_main_spawn_id
+
+# Points to the spawn id of the MI channel.  When testing with MI
+# running as the primary/main UI, this is the same as
+# gdb_main_spawn_id, but will be different when testing with MI
+# running on a secondary UI.
+global mi_spawn_id
+
 set MIFLAGS "-i=mi"
 
 set thread_selected_re "=thread-selected,id=\"\[0-9\]+\"\r\n"
@@ -46,7 +56,8 @@ proc mi_uncatched_gdb_exit {} {
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
     global verbose
-    global gdb_spawn_id
+    global gdb_spawn_id gdb_main_spawn_id
+    global mi_spawn_id inferior_spawn_id
     global gdb_prompt
     global mi_gdb_prompt
     global MIFLAGS
@@ -83,14 +94,103 @@ proc mi_uncatched_gdb_exit {} {
 	remote_close host
     }
     unset gdb_spawn_id
+    unset gdb_main_spawn_id
+    unset mi_spawn_id
+    unset inferior_spawn_id
+}
+
+# Create the PTY for the inferior process and tell GDB about it.
+
+proc mi_create_inferior_pty {} {
+    global mi_gdb_prompt
+    global inferior_spawn_id
+    global mi_inferior_tty_name
+
+    spawn -pty
+    set inferior_spawn_id $spawn_id
+    set tty_name $spawn_out(slave,name)
+    set mi_inferior_tty_name $tty_name
+
+    send_gdb "102-inferior-tty-set $tty_name\n"
+    gdb_expect 10 {
+	-re ".*102\\\^done\r\n$mi_gdb_prompt$" {
+	    verbose "redirect inferior output to new terminal device."
+	}
+	timeout {
+	    warning "Couldn't redirect inferior output." 2
+	}
+    }
+}
+
+# Switch the default spawn id to SPAWN_ID, so that mi_gdb_test
+# etc. default to using it.
+
+proc switch_gdb_spawn_id {spawn_id} {
+    global gdb_spawn_id
+    global board board_info
+
+    set gdb_spawn_id $spawn_id
+    set board [host_info name]
+    set board_info($board,fileid) $spawn_id
+}
+
+proc mi_gdb_start_separate_mi_tty { args } {
+    global gdb_prompt mi_gdb_prompt
+    global timeout
+    global gdb_spawn_id gdb_main_spawn_id mi_spawn_id
+    global inferior_spawn_id
+
+    set separate_inferior_pty 0
+
+    foreach arg $args {
+	if {$arg == "separate-inferior-tty"} {
+	    set separate_inferior_pty 1
+	}
+    }
+
+    gdb_start
+
+    # Create the new PTY for the MI UI.
+    spawn -pty
+    set mi_spawn_id $spawn_id
+    set mi_tty_name $spawn_out(slave,name)
+    gdb_test_multiple "new-ui mi $mi_tty_name\"" "new-ui" {
+	-re "New UI allocated\r\n$gdb_prompt $" {
+	}
+    }
+
+    # Switch to the MI channel.
+    set gdb_main_spawn_id $gdb_spawn_id
+    switch_gdb_spawn_id $mi_spawn_id
+
+    # Consume pending output and MI prompt.
+    gdb_expect {
+	-re "$mi_gdb_prompt$" {
+	}
+	default {
+	    perror "MI channel failed"
+	    remote_close host
+	    return -1
+	}
+    }
+
+    if {$separate_inferior_pty} {
+	mi_create_inferior_pty
+    }
+
+    mi_detect_async
+
+    return 0
 }
 
 #
-# default_mi_gdb_start [INFERIOR_PTY] -- start gdb running, default procedure
+# default_mi_gdb_start [FLAGS] -- start gdb running, default procedure
 #
-# INFERIOR_PTY should be set to separate-inferior-tty to have the inferior work 
-# with it's own PTY. If set to same-inferior-tty, the inferior shares GDB's PTY. 
-# The default value is same-inferior-tty.
+# If "separate-inferior-tty" is specified, the inferior works with
+# it's own PTY.
+#
+# If "separate-mi-tty" is specified, the gdb starts in CLI mode, with
+# MI running on a secondary UI, on its own tty.
 #
 # When running over NFS, particularly if running many simultaneous
 # tests on different hosts all using the same server, things can
@@ -103,8 +203,29 @@ proc default_mi_gdb_start { args } {
     global gdb_prompt
     global mi_gdb_prompt
     global timeout
-    global gdb_spawn_id inferior_spawn_id
+    global gdb_spawn_id gdb_main_spawn_id inferior_spawn_id mi_spawn_id
     global MIFLAGS
+    global SEPARATE_MI_TTY
+
+    if {[info exists FORCE_SEPARATE_MI_TTY]} {
+	set separate_mi_pty $FORCE_SEPARATE_MI_TTY
+    } else {
+	set separate_mi_pty 0
+    }
+
+    set separate_inferior_pty 0
+
+    foreach arg $args {
+	if {$arg == "separate-mi-tty"} {
+	    set separate_mi_pty 1
+	} elseif {$arg == "separate-inferior-tty"} {
+	    set separate_inferior_pty 1
+	}
+    }
+
+    if {$separate_mi_pty} {
+	return [eval mi_gdb_start_separate_mi_tty $args]
+    }
 
     gdb_stop_suppressing_tests
     set inferior_pty no-tty
@@ -112,12 +233,6 @@ proc default_mi_gdb_start { args } {
     # Set the default value, it may be overriden later by specific testfile.
     set use_gdb_stub [target_info exists use_gdb_stub]
 
-    if { [llength $args] == 1} {
-	set inferior_pty [lindex $args 0]
-    }
-
-    set separate_inferior_pty [string match $inferior_pty separate-inferior-tty]
-
     # Start SID.
     if { [info procs sid_start] != "" } {
 	verbose "Spawning SID"
@@ -182,6 +297,8 @@ proc default_mi_gdb_start { args } {
 	}
     }
     set gdb_spawn_id $res
+    set gdb_main_spawn_id $res
+    set mi_spawn_id $res
 
     # FIXME: mi output does not go through pagers, so these can be removed.
     # force the height to "unlimited", so no pagers get used
@@ -205,22 +322,8 @@ proc default_mi_gdb_start { args } {
 	}
     }
 
-    # Create the new PTY for the inferior process.
     if { $separate_inferior_pty } {
-	spawn -pty
-	global mi_inferior_tty_name
-	set inferior_spawn_id $spawn_id
-	set mi_inferior_tty_name $spawn_out(slave,name)
-
-	send_gdb "102-inferior-tty-set $mi_inferior_tty_name\n"
-	gdb_expect 10 {
-	    -re ".*102\\\^done\r\n$mi_gdb_prompt$" {
-		verbose "redirect inferior output to new terminal device."
-	    }
-	    timeout {
-		warning "Couldn't redirect inferior output." 2
-	    }
-	}
+	mi_create_inferior_pty
     }
 
     if {![info exists inferior_spawn_id]} {
@@ -237,7 +340,7 @@ proc default_mi_gdb_start { args } {
 # baseboard file.
 #
 proc mi_gdb_start { args } {
-  return [default_mi_gdb_start $args]
+  return [eval default_mi_gdb_start $args]
 }
 
 # Many of the tests depend on setting breakpoints at various places and
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 13/34] Make current_ui_out be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (11 preceding siblings ...)
  2016-05-06 12:36 ` [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI Pedro Alves
@ 2016-05-06 12:40 ` Pedro Alves
  2016-05-06 12:40 ` [PATCH v3 11/34] Make out and error streams " Pedro Alves
                   ` (22 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:40 UTC (permalink / raw)
  To: gdb-patches

Similarly to gdb_stdout&co.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* top.c: Call gen_ret_current_ui_field_ptr for current_uiout.
	* top.h (struct ui) <m_current_uiout>: New field.
	* ui-out.c (current_uiout): Delete.
	* ui-out.h (current_uiout): Delete.
	(current_ui_current_uiout_ptr): New declaration.
	(current_uiout): Reimplement as wrapper around
	current_ui_current_uiout_ptr.
---
 gdb/top.c    | 1 +
 gdb/top.h    | 3 +++
 gdb/ui-out.c | 5 -----
 gdb/ui-out.h | 3 ++-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/gdb/top.c b/gdb/top.c
index 733580f..2e6cf31 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -100,6 +100,7 @@ gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdout)
 gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdin)
 gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stderr)
 gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdlog)
+gen_ret_current_ui_field_ptr (struct ui_out *, current_uiout)
 
 /* Initialization file name for gdb.  This is host-dependent.  */
 
diff --git a/gdb/top.h b/gdb/top.h
index 31c4a8e..dfef32c 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -98,6 +98,9 @@ struct ui
      *_unfiltered.  In the very near future that restriction shall be
      removed - either call shall be unfiltered.  (cagney 1999-06-13).  */
   struct ui_file *m_gdb_stdlog;
+
+  /* The current ui_out.  */
+  struct ui_out *m_current_uiout;
 };
 
 /* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 4ea571b..3972a56 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -147,11 +147,6 @@ pop_level (struct ui_out *uiout,
   return uiout->level + 1;
 }
 
-/* FIXME: This should not be a global, but something passed down from main.c
-   or top.c.  */
-
-struct ui_out *current_uiout = NULL;
-
 /* These are the interfaces to implementation functions.  */
 
 static void uo_table_begin (struct ui_out *uiout, int nbrofcols,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 905d73c..9e1e74d 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -32,7 +32,8 @@ struct ui_file;
 
 /* FIXME: This should not be a global but something passed down from main.c
    or top.c.  */
-extern struct ui_out *current_uiout;
+extern struct ui_out **current_ui_current_uiout_ptr (void);
+#define current_uiout (*current_ui_current_uiout_ptr ())
 
 /* alignment enum */
 enum ui_align
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 23/34] New function should_print_stop_to_console
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (13 preceding siblings ...)
  2016-05-06 12:40 ` [PATCH v3 11/34] Make out and error streams " Pedro Alves
@ 2016-05-06 12:40 ` Pedro Alves
  2016-05-06 12:41 ` [PATCH v3 06/34] Introduce interpreter factories Pedro Alves
                   ` (20 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:40 UTC (permalink / raw)
  To: gdb-patches

There's code in the MI interpreter that decides whether a stop should
be sent to MI's console stream.  Move this check to the CLI
interpreter code, so that we can reuse it in both the CLI and TUI
interpreters.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-interp.c: Include gdbthread.h and thread-fsm.h.
	(should_print_stop_to_console): New function, factored out from
	mi_on_normal_stop_1.
	* cli/cli-interp.h (should_print_stop_to_console): Declare.
	* mi/mi-interp.c (mi_on_normal_stop_1): Use
	should_print_stop_to_console.  Pass it the current UI's console
	interpreter.
	* mi/mi-main.c (captured_mi_execute_command): Use the
	INTERP_CONSOLE symbol rather than explicit "console".
---
 gdb/cli/cli-interp.c | 34 ++++++++++++++++++++++++++++++++++
 gdb/cli/cli-interp.h |  5 +++++
 gdb/mi/mi-interp.c   | 27 ++++-----------------------
 gdb/mi/mi-main.c     |  2 +-
 4 files changed, 44 insertions(+), 24 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index 599507b..bbe287c 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -27,6 +27,8 @@
 #include "event-top.h"
 #include "infrun.h"
 #include "observer.h"
+#include "gdbthread.h"
+#include "thread-fsm.h"
 
 /* The console interpreter.  */
 struct cli_interp
@@ -51,6 +53,38 @@ static struct gdb_exception safe_execute_command (struct ui_out *uiout,
 						  char *command, 
 						  int from_tty);
 
+/* See cli-interp.h.
+
+   Breakpoint hits should always be mirrored to a console.  Deciding
+   what to mirror to a console wrt to breakpoints and random stops
+   gets messy real fast.  E.g., say "s" trips on a breakpoint.  We'd
+   clearly want to mirror the event to the console in this case.  But
+   what about more complicated cases like "s&; thread n; s&", and one
+   of those steps spawning a new thread, and that thread hitting a
+   breakpoint?  It's impossible in general to track whether the thread
+   had any relation to the commands that had been executed.  So we
+   just simplify and always mirror breakpoints and random events to
+   all consoles.
+
+   OTOH, we should print the source line to the console when stepping
+   or other similar commands, iff the step was started by that console
+   (or in MI's case, by a console command), but not if it was started
+   with MI's -exec-step or similar.  */
+
+int
+should_print_stop_to_console (struct interp *console_interp,
+			      struct thread_info *tp)
+{
+  if ((bpstat_what (tp->control.stop_bpstat).main_action
+       == BPSTAT_WHAT_STOP_NOISY)
+      || !(tp->thread_fsm != NULL
+	   && thread_fsm_finished_p (tp->thread_fsm))
+      || (tp->control.command_interp != NULL
+	  && tp->control.command_interp == console_interp))
+    return 1;
+  return 0;
+}
+
 /* Observers for several run control events.  If the interpreter is
    quiet (i.e., another interpreter is being run with
    interpreter-exec), print nothing.  */
diff --git a/gdb/cli/cli-interp.h b/gdb/cli/cli-interp.h
index 85be118..004b967 100644
--- a/gdb/cli/cli-interp.h
+++ b/gdb/cli/cli-interp.h
@@ -24,4 +24,9 @@ extern int cli_interpreter_supports_command_editing (struct interp *interp);
 
 extern void cli_interpreter_pre_command_loop (struct interp *self);
 
+/* Returns true if the current stop should be printed to
+   CONSOLE_INTERP.  */
+extern int should_print_stop_to_console (struct interp *interp,
+					 struct thread_info *tp);
+
 #endif
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 0b12a66..e9dfe8e 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -38,6 +38,7 @@
 #include "tracepoint.h"
 #include "cli-out.h"
 #include "thread-fsm.h"
+#include "cli/cli-interp.h"
 
 /* These are the interpreter setup, etc. functions for the MI
    interpreter.  */
@@ -662,6 +663,7 @@ mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
     {
       struct thread_info *tp;
       int core;
+      struct interp *console_interp;
 
       tp = inferior_thread ();
 
@@ -676,31 +678,10 @@ mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
 	}
       print_stop_event (mi_uiout);
 
-      /* Breakpoint hits should always be mirrored to the console.
-	 Deciding what to mirror to the console wrt to breakpoints and
-	 random stops gets messy real fast.  E.g., say "s" trips on a
-	 breakpoint.  We'd clearly want to mirror the event to the
-	 console in this case.  But what about more complicated cases
-	 like "s&; thread n; s&", and one of those steps spawning a
-	 new thread, and that thread hitting a breakpoint?  It's
-	 impossible in general to track whether the thread had any
-	 relation to the commands that had been executed.  So we just
-	 simplify and always mirror breakpoints and random events to
-	 the console.
-
-	 OTOH, we should print the source line to the console when
-	 stepping or other similar commands, iff the step was started
-	 by a console command, but not if it was started with
-	 -exec-step or similar.  */
-      if ((bpstat_what (tp->control.stop_bpstat).main_action
-	   == BPSTAT_WHAT_STOP_NOISY)
-	  || !(tp->thread_fsm != NULL
-	       && thread_fsm_finished_p (tp->thread_fsm))
-	  || (tp->control.command_interp != NULL
-	      && tp->control.command_interp != top_level_interpreter ()))
+      console_interp = interp_lookup (INTERP_CONSOLE);
+      if (should_print_stop_to_console (console_interp, tp))
 	print_stop_event (mi->cli_uiout);
 
-      tp = inferior_thread ();
       ui_out_field_int (mi_uiout, "thread-id", tp->global_num);
       if (non_stop)
 	{
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index a3b55a8746..6352f90 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -2040,7 +2040,7 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context)
 	/* Echo the command on the console.  */
 	fprintf_unfiltered (gdb_stdlog, "%s\n", context->command);
 	/* Call the "console" interpreter.  */
-	argv[0] = "console";
+	argv[0] = INTERP_CONSOLE;
 	argv[1] = context->command;
 	mi_cmd_interpreter_exec ("-interpreter-exec", argv, 2);
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 11/34] Make out and error streams be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (12 preceding siblings ...)
  2016-05-06 12:40 ` [PATCH v3 13/34] Make current_ui_out be per UI Pedro Alves
@ 2016-05-06 12:40 ` Pedro Alves
  2016-05-06 12:40 ` [PATCH v3 23/34] New function should_print_stop_to_console Pedro Alves
                   ` (21 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:40 UTC (permalink / raw)
  To: gdb-patches

stderr_fileopen () references stderr directly, which doesn't work when
we have a separate UI with its own stderr-like stream.  So this also
adds a "errstream" to "struct ui", and plumbs stderr_fileopen to take
a stream parameter.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-top.c (gdb_setup_readline): Pass the UI's outstream and
	errstream to stdout_fileopen and stderr_fileopen.
	* exceptions.c: Include top.h.
	(print_flush): Open the current UI's outstream file descriptor,
	instead of hardcoding file descriptor 1.
	* main.c (captured_main): Save the main UI's out and error
	streams.  Adjust stderr_fileopen call.
	* top.h (struct ui) <outstream, errstream>: New fields.
	* ui-file.c (stderr_fileopen): Add stream parameter.  Use it
	instead of stderr.
	* ui-file.h (stderr_fileopen): Add stream parameter and update
	comment.
---
 gdb/event-top.c  | 4 ++--
 gdb/exceptions.c | 4 +++-
 gdb/main.c       | 6 +++++-
 gdb/top.h        | 4 ++++
 gdb/ui-file.c    | 4 ++--
 gdb/ui-file.h    | 4 ++--
 6 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 1d36b81..08eb89d 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -1237,8 +1237,8 @@ gdb_setup_readline (void)
      mess it up here.  The sync stuff should really go away over
      time.  */
   if (!batch_silent)
-    gdb_stdout = stdio_fileopen (stdout);
-  gdb_stderr = stderr_fileopen ();
+    gdb_stdout = stdio_fileopen (ui->outstream);
+  gdb_stderr = stderr_fileopen (ui->errstream);
   gdb_stdlog = gdb_stderr;  /* for moment */
   gdb_stdtarg = gdb_stderr; /* for moment */
   gdb_stdtargerr = gdb_stderr; /* for moment */
diff --git a/gdb/exceptions.c b/gdb/exceptions.c
index 0e60050..9a10f66 100644
--- a/gdb/exceptions.c
+++ b/gdb/exceptions.c
@@ -26,10 +26,12 @@
 #include "ui-out.h"
 #include "serial.h"
 #include "gdbthread.h"
+#include "top.h"
 
 static void
 print_flush (void)
 {
+  struct ui *ui = current_ui;
   struct serial *gdb_stdout_serial;
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
 
@@ -56,7 +58,7 @@ print_flush (void)
   gdb_flush (gdb_stderr);
 
   /* 3.  The system-level buffer.  */
-  gdb_stdout_serial = serial_fdopen (1);
+  gdb_stdout_serial = serial_fdopen (fileno (ui->outstream));
   if (gdb_stdout_serial)
     {
       serial_drain_output (gdb_stdout_serial);
diff --git a/gdb/main.c b/gdb/main.c
index d862759..58e510e 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -507,7 +507,11 @@ captured_main (void *data)
   ndir = 0;
 
   saved_command_line = (char *) xstrdup ("");
+
   ui->instream = stdin;
+  ui->outstream = stdout;
+  ui->errstream = stderr;
+
   ui->input_fd = fileno (stdin);
 
 #ifdef __MINGW32__
@@ -517,7 +521,7 @@ captured_main (void *data)
 #endif
 
   gdb_stdout = stdio_fileopen (stdout);
-  gdb_stderr = stderr_fileopen ();
+  gdb_stderr = stderr_fileopen (stderr);
 
   gdb_stdlog = gdb_stderr;	/* for moment */
   gdb_stdtarg = gdb_stderr;	/* for moment */
diff --git a/gdb/top.h b/gdb/top.h
index c50c0c9..31c4a8e 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -73,6 +73,10 @@ struct ui
      Set to NULL if we are executing a user-defined command or
      interacting via a GUI.  */
   FILE *instream;
+  /* Standard output stream.  */
+  FILE *outstream;
+  /* Standard error stream.  */
+  FILE *errstream;
 
   /* The file descriptor for the input stream, so that we can register
      it with the event loop.  */
diff --git a/gdb/ui-file.c b/gdb/ui-file.c
index 4260710..a977f89 100644
--- a/gdb/ui-file.c
+++ b/gdb/ui-file.c
@@ -681,9 +681,9 @@ stderr_file_fputs (const char *linebuffer, struct ui_file *file)
 #endif
 
 struct ui_file *
-stderr_fileopen (void)
+stderr_fileopen (FILE *stream)
 {
-  struct ui_file *ui_file = stdio_fileopen (stderr);
+  struct ui_file *ui_file = stdio_fileopen (stream);
 
 #ifdef __MINGW32__
   /* There is no real line-buffering on Windows, see
diff --git a/gdb/ui-file.h b/gdb/ui-file.h
index a6ec135..f6df572 100644
--- a/gdb/ui-file.h
+++ b/gdb/ui-file.h
@@ -135,8 +135,8 @@ extern struct ui_file *mem_fileopen (void);
 /* Open/create a STDIO based UI_FILE using the already open FILE.  */
 extern struct ui_file *stdio_fileopen (FILE *file);
 
-/* Create a ui_file from stderr.  */
-extern struct ui_file *stderr_fileopen (void);
+/* Likewise, for stderr-like streams.  */
+extern struct ui_file *stderr_fileopen (FILE *file);
 
 
 /* Open NAME returning an STDIO based UI_FILE.  */
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 06/34] Introduce interpreter factories
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (14 preceding siblings ...)
  2016-05-06 12:40 ` [PATCH v3 23/34] New function should_print_stop_to_console Pedro Alves
@ 2016-05-06 12:41 ` Pedro Alves
  2016-05-18 19:18   ` Simon Marchi
  2016-05-18 19:20   ` Simon Marchi
  2016-05-06 12:42 ` [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels Pedro Alves
                   ` (19 subsequent siblings)
  35 siblings, 2 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:41 UTC (permalink / raw)
  To: gdb-patches

If every UI instance has its own set of interpreters, then the current
scheme of creating the interpreters at GDB initialization time no
longer works.  We need to create them whenever a new UI instance is
created.

The scheme implemented here has each interpreter register an factory
callback that when called creates a new instance of a specific type.
Then, when some code in gdb looks up an interpreter (always by name),
if there's none yet, the factory method is called to construct one.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-interp.c (cli_uiout): Delete, moved into ...
	(struct cli_interp): ... this new structure.
	(cli_on_normal_stop, cli_on_signal_received)
	(cli_on_end_stepping_range, cli_on_signal_exited, cli_on_exited)
	(cli_on_no_history): Use interp_ui_out.
	(cli_interpreter_init): If top level, set the cli_interp global.
	(cli_interpreter_init): Return the interp's data instead of NULL.
	(cli_interpreter_resume, cli_interpreter_exec, cli_ui_out): Adjust
	to cli_uiout being in the interpreter's data.
	(cli_interp_procs): New, factored out from _initialize_cli_interp.
	(cli_interp_factory): New function.
	(_initialize_cli_interp): Call interp_factory_register.
	* interps.c (interp_new): Add parameter 'data'.  Store it.
	(struct interp_factory): New function.
	(interp_factory_p): New typedef.  Define a VEC_P.
	(interpreter_factories): New global.
	(interp_factory_register): New function.
	(interp_add): Use interp_lookup_existing.
	(interp_lookup): Rename to ...
	(interp_lookup_existing): ... this.  Don't check for NULL or empty
	name here.
	(interp_lookup): Reimplement.
	(interpreter_completer): Complete on registered interpreter
	factories instead of interpreters.
	* interps.h (interp_factory_func): New typedef.
	(interp_factory_register): Declare.
	(interp_new): Adjust.
	(interp_lookup): Declare.
	* mi/mi-interp.c (mi_interp_procs): New, factored out from
	_initialize_mi_interp.
	(mi_interp_factory): New function.
	* tui/tui-interp.c (tui_init): If top level, set the tui_interp
	global.
	(tui_interp_procs): New.
	(tui_interp_factory): New function.
	(_initialize_tui_interp): Call interp_factory_register.
---
 gdb/cli/cli-interp.c |  87 ++++++++++++++++++++++++++----------------
 gdb/interps.c        | 105 +++++++++++++++++++++++++++++++++++++++++++--------
 gdb/interps.h        |  21 ++++++++++-
 gdb/mi/mi-interp.c   |  40 ++++++++++++--------
 gdb/tui/tui-interp.c |  38 ++++++++++++-------
 5 files changed, 214 insertions(+), 77 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index dfbd808..ac12a4c 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -26,9 +26,14 @@
 #include "infrun.h"
 #include "observer.h"
 
-/* These are the ui_out and the interpreter for the console
-   interpreter.  */
-struct ui_out *cli_uiout;
+/* The console interpreter.  */
+struct cli_interp
+{
+  /* The ui_out for the console interpreter.  */
+  struct ui_out *cli_uiout;
+};
+
+/* The interpreter for the console interpreter.  */
 static struct interp *cli_interp;
 
 /* Longjmp-safe wrapper for "execute_command".  */
@@ -48,7 +53,7 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame)
   if (!interp_quiet_p (cli_interp))
     {
       if (print_frame)
-	print_stop_event (cli_uiout);
+	print_stop_event (interp_ui_out (cli_interp));
     }
 }
 
@@ -58,7 +63,7 @@ static void
 cli_on_signal_received (enum gdb_signal siggnal)
 {
   if (!interp_quiet_p (cli_interp))
-    print_signal_received_reason (cli_uiout, siggnal);
+    print_signal_received_reason (interp_ui_out (cli_interp), siggnal);
 }
 
 /* Observer for the end_stepping_range notification.  */
@@ -67,7 +72,7 @@ static void
 cli_on_end_stepping_range (void)
 {
   if (!interp_quiet_p (cli_interp))
-    print_end_stepping_range_reason (cli_uiout);
+    print_end_stepping_range_reason (interp_ui_out (cli_interp));
 }
 
 /* Observer for the signalled notification.  */
@@ -76,7 +81,7 @@ static void
 cli_on_signal_exited (enum gdb_signal siggnal)
 {
   if (!interp_quiet_p (cli_interp))
-    print_signal_exited_reason (cli_uiout, siggnal);
+    print_signal_exited_reason (interp_ui_out (cli_interp), siggnal);
 }
 
 /* Observer for the exited notification.  */
@@ -85,7 +90,7 @@ static void
 cli_on_exited (int exitstatus)
 {
   if (!interp_quiet_p (cli_interp))
-    print_exited_reason (cli_uiout, exitstatus);
+    print_exited_reason (interp_ui_out (cli_interp), exitstatus);
 }
 
 /* Observer for the no_history notification.  */
@@ -94,7 +99,7 @@ static void
 cli_on_no_history (void)
 {
   if (!interp_quiet_p (cli_interp))
-    print_no_history_reason (cli_uiout);
+    print_no_history_reason (interp_ui_out (cli_interp));
 }
 
 /* Observer for the sync_execution_done notification.  */
@@ -120,6 +125,9 @@ cli_on_command_error (void)
 static void *
 cli_interpreter_init (struct interp *self, int top_level)
 {
+  if (top_level)
+    cli_interp = self;
+
   /* If changing this, remember to update tui-interp.c as well.  */
   observer_attach_normal_stop (cli_on_normal_stop);
   observer_attach_end_stepping_range (cli_on_end_stepping_range);
@@ -130,12 +138,13 @@ cli_interpreter_init (struct interp *self, int top_level)
   observer_attach_sync_execution_done (cli_on_sync_execution_done);
   observer_attach_command_error (cli_on_command_error);
 
-  return NULL;
+  return interp_data (self);
 }
 
 static int
 cli_interpreter_resume (void *data)
 {
+  struct cli_interp *cli = (struct cli_interp *) data;
   struct ui_file *stream;
 
   /*sync_execution = 1; */
@@ -144,17 +153,17 @@ cli_interpreter_resume (void *data)
      previously writing to gdb_stdout, then set it to the new
      gdb_stdout afterwards.  */
 
-  stream = cli_out_set_stream (cli_uiout, gdb_stdout);
+  stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout);
   if (stream != gdb_stdout)
     {
-      cli_out_set_stream (cli_uiout, stream);
+      cli_out_set_stream (cli->cli_uiout, stream);
       stream = NULL;
     }
 
   gdb_setup_readline ();
 
   if (stream != NULL)
-    cli_out_set_stream (cli_uiout, gdb_stdout);
+    cli_out_set_stream (cli->cli_uiout, gdb_stdout);
 
   return 1;
 }
@@ -169,6 +178,7 @@ cli_interpreter_suspend (void *data)
 static struct gdb_exception
 cli_interpreter_exec (void *data, const char *command_str)
 {
+  struct cli_interp *cli = (struct cli_interp *) data;
   struct ui_file *old_stream;
   struct gdb_exception result;
 
@@ -184,9 +194,9 @@ cli_interpreter_exec (void *data, const char *command_str)
 
      It is important that it gets reset everytime, since the user
      could set gdb to use a different interpreter.  */
-  old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
-  result = safe_execute_command (cli_uiout, str, 1);
-  cli_out_set_stream (cli_uiout, old_stream);
+  old_stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout);
+  result = safe_execute_command (cli->cli_uiout, str, 1);
+  cli_out_set_stream (cli->cli_uiout, old_stream);
   return result;
 }
 
@@ -222,7 +232,34 @@ safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty)
 static struct ui_out *
 cli_ui_out (struct interp *self)
 {
-  return cli_uiout;
+  struct cli_interp *cli = (struct cli_interp *) interp_data (self);
+
+  return cli->cli_uiout;
+}
+
+/* The CLI interpreter's vtable.  */
+
+static const struct interp_procs cli_interp_procs = {
+  cli_interpreter_init,		/* init_proc */
+  cli_interpreter_resume,	/* resume_proc */
+  cli_interpreter_suspend,	/* suspend_proc */
+  cli_interpreter_exec,		/* exec_proc */
+  cli_ui_out,			/* ui_out_proc */
+  NULL,                       	/* set_logging_proc */
+  cli_command_loop            	/* command_loop_proc */
+};
+
+/* Factory for CLI interpreters.  */
+
+static struct interp *
+cli_interp_factory (const char *name, struct ui *ui)
+{
+  struct cli_interp *cli = XNEW (struct cli_interp);
+
+  /* Create a default uiout builder for the CLI.  */
+  cli->cli_uiout = cli_out_new (gdb_stdout);
+
+  return interp_new (name, &cli_interp_procs, cli);
 }
 
 /* Standard gdb initialization hook.  */
@@ -231,19 +268,5 @@ extern initialize_file_ftype _initialize_cli_interp; /* -Wmissing-prototypes */
 void
 _initialize_cli_interp (void)
 {
-  static const struct interp_procs procs = {
-    cli_interpreter_init,	/* init_proc */
-    cli_interpreter_resume,	/* resume_proc */
-    cli_interpreter_suspend,	/* suspend_proc */
-    cli_interpreter_exec,	/* exec_proc */
-    cli_ui_out,			/* ui_out_proc */
-    NULL,                       /* set_logging_proc */
-    cli_command_loop            /* command_loop_proc */
-  };
-
-  /* Create a default uiout builder for the CLI.  */
-  cli_uiout = cli_out_new (gdb_stdout);
-  cli_interp = interp_new (INTERP_CONSOLE, &procs);
-
-  interp_add (cli_interp);
+  interp_factory_register (INTERP_CONSOLE, cli_interp_factory);
 }
diff --git a/gdb/interps.c b/gdb/interps.c
index 7f57132..ca8512b 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -91,18 +91,20 @@ struct interp
 
 void _initialize_interpreter (void);
 
+static struct interp *interp_lookup_existing (const char *name);
+
 /* interp_new - This allocates space for a new interpreter,
    fills the fields from the inputs, and returns a pointer to the
    interpreter.  */
 struct interp *
-interp_new (const char *name, const struct interp_procs *procs)
+interp_new (const char *name, const struct interp_procs *procs, void *data)
 {
   struct interp *new_interp;
 
   new_interp = XNEW (struct interp);
 
   new_interp->name = xstrdup (name);
-  new_interp->data = NULL;
+  new_interp->data = data;
   new_interp->quiet_p = 0;
   new_interp->procs = procs;
   new_interp->inited = 0;
@@ -113,6 +115,49 @@ interp_new (const char *name, const struct interp_procs *procs)
   return new_interp;
 }
 
+/* An interpreter factory.  Maps an interpreter name to the factory
+   function that instantiates an interpreter by that name.  */
+
+struct interp_factory
+{
+  /* This is the name in "-i=INTERP" and "interpreter-exec INTERP".  */
+  const char *name;
+
+  /* The function that creates the interpreter.  */
+  interp_factory_func func;
+};
+
+typedef struct interp_factory *interp_factory_p;
+DEF_VEC_P(interp_factory_p);
+
+/* The registered interpreter factories.  */
+static VEC(interp_factory_p) *interpreter_factories = NULL;
+
+/* See interps.h.  */
+
+void
+interp_factory_register (const char *name, interp_factory_func func)
+{
+  struct interp_factory *f;
+  int ix;
+
+  /* Assert that no factory for NAME is already registered.  */
+  for (ix = 0;
+       VEC_iterate (interp_factory_p, interpreter_factories, ix, f);
+       ++ix)
+    if (strcmp (f->name, name) == 0)
+      {
+	internal_error (__FILE__, __LINE__,
+			_("interpreter factory already registered: \"%s\"\n"),
+			name);
+      }
+
+  f = XNEW (struct interp_factory);
+  f->name = name;
+  f->func = func;
+  VEC_safe_push (interp_factory_p, interpreter_factories, f);
+}
+
 /* Add interpreter INTERP to the gdb interpreter list.  The
    interpreter must not have previously been added.  */
 void
@@ -120,7 +165,7 @@ interp_add (struct interp *interp)
 {
   struct ui_interp_info *ui_interp = get_current_interp_info ();
 
-  gdb_assert (interp_lookup (interp->name) == NULL);
+  gdb_assert (interp_lookup_existing (interp->name) == NULL);
 
   interp->next = ui_interp->interp_list;
   ui_interp->interp_list = interp;
@@ -219,18 +264,15 @@ interp_set (struct interp *interp, int top_level)
   return 1;
 }
 
-/* interp_lookup - Looks up the interpreter for NAME.  If no such
-   interpreter exists, return NULL, otherwise return a pointer to the
-   interpreter.  */
-struct interp *
-interp_lookup (const char *name)
+/* Look up the interpreter for NAME.  If no such interpreter exists,
+   return NULL, otherwise return a pointer to the interpreter.  */
+
+static struct interp *
+interp_lookup_existing (const char *name)
 {
   struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *interp;
 
-  if (name == NULL || strlen (name) == 0)
-    return NULL;
-
   for (interp = ui_interp->interp_list;
        interp != NULL;
        interp = interp->next)
@@ -242,6 +284,37 @@ interp_lookup (const char *name)
   return NULL;
 }
 
+/* See interps.h.  */
+
+struct interp *
+interp_lookup (const char *name)
+{
+  struct ui *ui = current_ui;
+  struct interp_factory *factory;
+  struct interp *interp;
+  int ix;
+
+  if (name == NULL || strlen (name) == 0)
+    return NULL;
+
+  /* Only create each interpreter once per top level.  */
+  interp = interp_lookup_existing (name);
+  if (interp != NULL)
+    return interp;
+
+  for (ix = 0;
+       VEC_iterate (interp_factory_p, interpreter_factories, ix, factory);
+       ++ix)
+    if (strcmp (factory->name, name) == 0)
+      {
+	interp = factory->func (name, ui);
+	interp_add (interp);
+	return interp;
+      }
+
+  return NULL;
+}
+
 /* Returns the current interpreter.  */
 
 struct ui_out *
@@ -469,15 +542,15 @@ static VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
-  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp_factory *interp;
   int textlen;
   VEC (char_ptr) *matches = NULL;
-  struct interp *interp;
+  int ix;
 
   textlen = strlen (text);
-  for (interp = ui_interp->interp_list;
-       interp != NULL;
-       interp = interp->next)
+  for (ix = 0;
+       VEC_iterate (interp_factory_p, interpreter_factories, ix, interp);
+       ++ix)
     {
       if (strncmp (interp->name, text, textlen) == 0)
 	{
diff --git a/gdb/interps.h b/gdb/interps.h
index f0badc5..3065fdf 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -24,6 +24,17 @@
 
 struct ui_out;
 struct interp;
+struct ui;
+
+typedef struct interp *(*interp_factory_func) (const char *interp,
+					       struct ui *ui);
+
+/* Each interpreter kind (CLI, MI, etc.) registers itself with a call
+   to this function, passing along its name, and a pointer to a
+   function that creates a new instance of an interpreter with that
+   name.  */
+extern void interp_factory_register (const char *name,
+				     interp_factory_func func);
 
 extern int interp_resume (struct interp *interp);
 extern int interp_suspend (struct interp *interp);
@@ -64,10 +75,18 @@ struct interp_procs
   interp_command_loop_ftype *command_loop_proc;
 };
 
-extern struct interp *interp_new (const char *name, const struct interp_procs *procs);
+extern struct interp *interp_new (const char *name,
+				  const struct interp_procs *procs,
+				  void *data);
 extern void interp_add (struct interp *interp);
 extern int interp_set (struct interp *interp, int top_level);
+
+/* Look up the interpreter for NAME, creating one if none exists yet.
+   If NAME is not a interpreter type previously registered with
+   interp_factory_register, return NULL; otherwise return a pointer to
+   the interpreter.  */
 extern struct interp *interp_lookup (const char *name);
+
 extern struct ui_out *interp_ui_out (struct interp *interp);
 extern void *interp_data (struct interp *interp);
 extern const char *interp_name (struct interp *interp);
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 7c82950..8ba6110 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -1219,25 +1219,35 @@ mi_set_logging (struct interp *interp, int start_log,
   return 1;
 }
 
+/* The MI interpreter's vtable.  */
+
+static const struct interp_procs mi_interp_procs =
+{
+  mi_interpreter_init,		/* init_proc */
+  mi_interpreter_resume,	/* resume_proc */
+  mi_interpreter_suspend,	/* suspend_proc */
+  mi_interpreter_exec,		/* exec_proc */
+  mi_ui_out, 			/* ui_out_proc */
+  mi_set_logging,		/* set_logging_proc */
+  mi_command_loop		/* command_loop_proc */
+};
+
+/* Factory for MI interpreters.  */
+
+static struct interp *
+mi_interp_factory (const char *name, struct ui *ui)
+{
+  return interp_new (name, &mi_interp_procs, NULL);
+}
+
 extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
 
 void
 _initialize_mi_interp (void)
 {
-  static const struct interp_procs procs =
-    {
-      mi_interpreter_init,	/* init_proc */
-      mi_interpreter_resume,	/* resume_proc */
-      mi_interpreter_suspend,	/* suspend_proc */
-      mi_interpreter_exec,	/* exec_proc */
-      mi_ui_out, 		/* ui_out_proc */
-      mi_set_logging,		/* set_logging_proc */
-      mi_command_loop		/* command_loop_proc */
-    };
-
   /* The various interpreter levels.  */
-  interp_add (interp_new (INTERP_MI1, &procs));
-  interp_add (interp_new (INTERP_MI2, &procs));
-  interp_add (interp_new (INTERP_MI3, &procs));
-  interp_add (interp_new (INTERP_MI, &procs));
+  interp_factory_register (INTERP_MI1, mi_interp_factory);
+  interp_factory_register (INTERP_MI2, mi_interp_factory);
+  interp_factory_register (INTERP_MI3, mi_interp_factory);
+  interp_factory_register (INTERP_MI, mi_interp_factory);
 }
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 7a0da48..8afe46c 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -138,6 +138,9 @@ tui_init (struct interp *self, int top_level)
   /* Install exit handler to leave the screen in a good shape.  */
   atexit (tui_exit);
 
+  if (top_level)
+    tui_interp = self;
+
   tui_initialize_static_data ();
 
   tui_initialize_io ();
@@ -207,25 +210,34 @@ tui_exec (void *data, const char *command_str)
   internal_error (__FILE__, __LINE__, _("tui_exec called"));
 }
 
+/* The TUI interpreter's vtable.  */
+
+static const struct interp_procs tui_interp_procs = {
+  tui_init,
+  tui_resume,
+  tui_suspend,
+  tui_exec,
+  tui_ui_out,
+  NULL,
+  cli_command_loop
+};
+
+/* Factory for TUI interpreters.  */
+
+static struct interp *
+tui_interp_factory (const char *name, struct ui *ui)
+{
+  return interp_new (name, &tui_interp_procs, NULL);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_tui_interp;
 
 void
 _initialize_tui_interp (void)
 {
-  static const struct interp_procs procs = {
-    tui_init,
-    tui_resume,
-    tui_suspend,
-    tui_exec,
-    tui_ui_out,
-    NULL,
-    cli_command_loop
-  };
-
-  /* Create a default uiout builder for the TUI.  */
-  tui_interp = interp_new (INTERP_TUI, &procs);
-  interp_add (tui_interp);
+  interp_factory_register (INTERP_TUI, tui_interp_factory);
+
   if (interpreter_p && strcmp (interpreter_p, INTERP_TUI) == 0)
     tui_start_enabled = 1;
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (15 preceding siblings ...)
  2016-05-06 12:41 ` [PATCH v3 06/34] Introduce interpreter factories Pedro Alves
@ 2016-05-06 12:42 ` Pedro Alves
  2016-05-06 13:04   ` Eli Zaretskii
  2016-05-06 12:43 ` [PATCH v3 04/34] Make gdb_stdout&co be per UI Pedro Alves
                   ` (18 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:42 UTC (permalink / raw)
  To: gdb-patches

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* NEWS: Mention support for running interpreters on separate
	channels and the new new-ui command.

gdb/doc/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.texinfo (Interpreters): Update intepreter-exec section,
	document new-ui and explain use case.
---
 gdb/doc/gdb.texinfo | 55 +++++++++++++++++++++++++++++++++++++++++++----------
 gdb/NEWS            | 16 ++++++++++++++++
 2 files changed, 61 insertions(+), 10 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f74c41c..c89486d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24805,18 +24805,11 @@ The @sc{gdb/mi} interface included in @value{GDBN} 5.1, 5.2, and 5.3.
 @end table
 
 @cindex invoke another interpreter
-The interpreter being used by @value{GDBN} may not be dynamically
-switched at runtime.  Although possible, this could lead to a very
-precarious situation.  Consider an IDE using @sc{gdb/mi}.  If a user
-enters the command "interpreter-set console" in a console view,
-@value{GDBN} would switch to using the console interpreter, rendering
-the IDE inoperable!
 
 @kindex interpreter-exec
-Although you may only choose a single interpreter at startup, you may execute
-commands in any interpreter from the current interpreter using the appropriate
-command.  If you are running the console interpreter, simply use the
-@code{interpreter-exec} command:
+You may execute commands in any interpreter from the current
+interpreter using the appropriate command.  If you are running the
+console interpreter, simply use the @code{interpreter-exec} command:
 
 @smallexample
 interpreter-exec mi "-data-list-register-names"
@@ -24825,6 +24818,48 @@ interpreter-exec mi "-data-list-register-names"
 @sc{gdb/mi} has a similar command, although it is only available in versions of
 @value{GDBN} which support @sc{gdb/mi} version 2 (or greater).
 
+Note that @code{interpreter-exec} only changes the interpreter for the
+duration of the specified command.  It does change the interpreter
+permanently.
+
+@cindex start a new independent interpreter
+
+Although you may only choose a single interpreter at startup, it is
+possible to run an independent interpreter on a separate channel.
+
+For example, consider a debugger GUI or IDE that wants to provide a
+@value{GDBN} console view.  It may do so by embedding a terminal
+window widget in its GUI, starting @value{GDBN} with the default
+console interpreter running on that terminal, and then opening a
+secondary communication channel running the MI interpreter.  The
+console interpreter created by @value{GDBN} at startup handles
+commands the user types in the terminal widget, while the GUI controls
+and synchronizes state with @value{GDBN} using the separate MI
+channel.
+
+To start a new secondary @dfn{user interface} channel running MI, use
+the @code{new-ui} command:
+
+@kindex new-ui
+@cindex new user interface
+@smallexample
+new-ui @var{interpreter} @var{tty}
+@end smallexample
+
+The @var{interpreter} parameter specifies the interpreter to run.
+This accepts the same values as the @code{interpreter-exec} command.
+For example, @samp{console}, @samp{mi}, @samp{mi2}, etc.  The
+@var{tty} parameter specifies the name of the bidirectional file the
+interpreter uses for input/output, usually the name of a
+pseudoterminal slave on Unix systems.  For example:
+
+@smallexample
+(@value{GDBP}) new-ui mi /dev/pts/9
+@end smallexample
+
+@noindent
+runs an MI interpreter on @file{/dev/pts/9}.
+
 @node TUI
 @chapter @value{GDBN} Text User Interface
 @cindex TUI
diff --git a/gdb/NEWS b/gdb/NEWS
index 7bf1e1a..c280300 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,18 @@
    Bounds: [lower = 0x7fffffffc390, upper = 0x7fffffffc3a3]
    0x0000000000400d7c in upper () at i386-mpx-sigsegv.c:68
 
+* Support for running interpreters on separate channels
+
+  GDB now supports a new mechanism that allows frontends to provide
+  fully featured GDB console views, as a better alternative to
+  building such views on top of the "-interpreter-exec console"
+  command.  See the new "new-ui" command below.  With that command,
+  frontends can now start GDB in console mode running on an embedded
+  terminal widget, and open a separate MI channel for the usual MI
+  control and synchronization invisible to the user.  In this way, GDB
+  handles line editing, history, tab completion, etc. in the console
+  all by itself.
+
 * New commands
 
 skip -file file
@@ -40,6 +52,10 @@ skip -rfunction regular-expression
 maint info line-table REGEXP
   Display the contents of GDB's internal line table data struture.
 
+new-ui INTERP TTY
+  Start a new user interface instance running INTERP as interpreter,
+  using the TTY file for input/output.
+
 * Support for tracepoints and fast tracepoints on s390-linux and s390x-linux
   was added in GDBserver, including JIT compiling fast tracepoint's
   conditional expression bytecode into native code.
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 28/34] Make stdin be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (20 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 25/34] Only send sync execution command output to the UI that ran the command Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-06 12:43 ` [PATCH v3 05/34] Make the interpreters " Pedro Alves
                   ` (13 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

This commit makes each UI have its own "stdin" stream pointer.  This
is used to determine whether the "from_tty" argument to
execute_command, etc. should be true.

Related, this commit makes input_from_terminal_p take an UI parameter,
and then avoids the gdb_has_a_terminal in it.  gdb_has_a_terminal only
returns info on gdb's own main/primary terminal (the real stdin).
However, the places that call input_from_terminal_p really want to
know is whether the command came from an interactive tty.  This patch
thus renames input_from_terminal_p to input_interactive_p for clarity,
and then makes input_interactive_p check for "set interactive" itself,
along with ISATTY, instead of calling gdb_has_a_terminal.  Actually,
quit_force wants to call input_interactive_p _after_ stdin is closed,
we can't call ISATTY that late.  So instead we save the result of
ISATTY in a field of the UI.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-script.c (read_next_line): Adjust to per-UI stdin.
	(read_command_lines): Use input_interactive_p instead of
	input_from_terminal_p.
	* defs.h (struct ui): Forward declare.
	(input_from_terminal_p): Rename to ...
	(input_interactive_p): ... this.
	* event-top.c (stdin_event_handler): Pass 0 as from_tty argument
	to quit_command.
	(command_handler): Adjust to per-UI stdin.
	(handle_line_of_input): Adjust to per-UI stdin and use
	input_interactive_p instead of ISATTY and input_from_terminal_p.
	(gdb_readline_no_editing_callback): Adjust to per-UI stdin.
	(command_line_handler): Always pass true as "from_tty" parameter
	of handle_line_of_input and execute_command.
	(async_sigterm_handler): Pass 0 as from_tty argument to
	quit_command.
	* inflow.c (interactive_mode, show_interactive_mode): Moved to ...
	(gdb_has_a_terminal): Don't check interactive_mode here.
	(_initialize_inflow): Don't install "set interactive-mode" here.
	* main.c (captured_command_loop): Adjust to per-UI stdin.
	* mi/mi-interp.c (mi_execute_command_wrapper): Adjust to per-UI
	stdin.
	* top.c (new_ui): Save the stdin stream and whether it's a tty.
	(dont_repeat): Adjust to per-UI stdin.
	(command_line_input): Adjust to per-UI stdin and to use
	input_interactive_p.
	(quit_force): Write history if any UI supports interactive input.
	(interactive_mode, show_interactive_mode): Move here, from
	inflow.c.
	(input_from_terminal_p): Rename to ...
	(input_interactive_p): ... this, and check the "interactive_mode"
	global instead of calling gdb_has_a_terminal.
	(_initialize_top): Install "set interactive-mode" here.
	* top.h (struct ui) <stdin_stream, input_interactive_p>: New
	fields.
	* utils.c (quit): Pass 0 as from_tty argument to quit_force.
	(defaulted_query): Adjust to per-UI stdin and to use
	input_interactive_p.
---
 gdb/cli/cli-script.c | 10 +++---
 gdb/defs.h           |  4 ++-
 gdb/event-top.c      | 23 +++++++------
 gdb/inflow.c         | 35 --------------------
 gdb/main.c           |  2 +-
 gdb/mi/mi-interp.c   |  2 +-
 gdb/top.c            | 93 +++++++++++++++++++++++++++++++++++++++-------------
 gdb/top.h            |  8 +++++
 gdb/utils.c          |  5 +--
 9 files changed, 103 insertions(+), 79 deletions(-)

diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 0507c55..579d0a4 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -935,12 +935,13 @@ read_next_line (void)
   struct ui *ui = current_ui;
   char *prompt_ptr, control_prompt[256];
   int i = 0;
+  int from_tty = ui->instream == ui->stdin_stream;
 
   if (control_level >= 254)
     error (_("Control nesting too deep!"));
 
   /* Set a prompt based on the nesting of the control commands.  */
-  if (ui->instream == stdin
+  if (from_tty
       || (ui->instream == 0 && deprecated_readline_hook != NULL))
     {
       for (i = 0; i < control_level; i++)
@@ -952,7 +953,7 @@ read_next_line (void)
   else
     prompt_ptr = NULL;
 
-  return command_line_input (prompt_ptr, ui->instream == stdin, "commands");
+  return command_line_input (prompt_ptr, from_tty, "commands");
 }
 
 /* Process one input line.  If the command is an "end", return such an
@@ -1256,7 +1257,7 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands,
 {
   struct command_line *head;
 
-  if (from_tty && input_from_terminal_p ())
+  if (from_tty && input_interactive_p (current_ui))
     {
       if (deprecated_readline_begin_hook)
 	{
@@ -1287,7 +1288,8 @@ read_command_lines (char *prompt_arg, int from_tty, int parse_commands,
       do_cleanups (old_chain);
     }
 
-  if (deprecated_readline_end_hook && from_tty && input_from_terminal_p ())
+  if (from_tty && input_interactive_p (current_ui)
+      && deprecated_readline_end_hook)
     {
       (*deprecated_readline_end_hook) ();
     }
diff --git a/gdb/defs.h b/gdb/defs.h
index 482ef1c..e8945ab 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -323,7 +323,9 @@ extern char *command_line_input (const char *, int, char *);
 
 extern void print_prompt (void);
 
-extern int input_from_terminal_p (void);
+struct ui;
+
+extern int input_interactive_p (struct ui *);
 
 extern int info_verbose;
 
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 777823e..072ad2a 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -518,7 +518,7 @@ stdin_event_handler (int error, gdb_client_data client_data)
 	{
 	  /* If stdin died, we may as well kill gdb.  */
 	  printf_unfiltered (_("error detected on stdin\n"));
-	  quit_command ((char *) 0, stdin == ui->instream);
+	  quit_command ((char *) 0, 0);
 	}
       else
 	{
@@ -589,7 +589,7 @@ command_handler (char *command)
   struct cleanup *stat_chain;
   char *c;
 
-  if (ui->instream == stdin)
+  if (ui->instream == ui->stdin_stream)
     reinitialize_more_filter ();
 
   stat_chain = make_command_stats_cleanup (1);
@@ -599,7 +599,7 @@ command_handler (char *command)
     ;
   if (c[0] != '#')
     {
-      execute_command (command, ui->instream == stdin);
+      execute_command (command, ui->instream == ui->stdin_stream);
 
       /* Do any commands attached to breakpoint we stopped at.  */
       bpstat_do_actions ();
@@ -667,6 +667,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
 		      char *rl, int repeat, char *annotation_suffix)
 {
   struct ui *ui = current_ui;
+  int from_tty = ui->instream == ui->stdin_stream;
   char *p1;
   char *cmd;
 
@@ -681,7 +682,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
      command, but leave ownership of memory to the buffer .  */
   cmd_line_buffer->used_size = 0;
 
-  if (annotation_level > 1 && ui->instream == stdin)
+  if (from_tty && annotation_level > 1)
     {
       printf_unfiltered (("\n\032\032post-"));
       puts_unfiltered (annotation_suffix);
@@ -698,8 +699,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
     }
 
   /* Do history expansion if that is wished.  */
-  if (history_expansion_p && ui->instream == stdin
-      && ISATTY (ui->instream))
+  if (history_expansion_p && from_tty && input_interactive_p (current_ui))
     {
       char *history_value;
       int expanded;
@@ -743,7 +743,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
      and then later fetch it from the value history and remove the
      '#'.  The kill ring is probably better, but some people are in
      the habit of commenting things out.  */
-  if (*cmd != '\0' && input_from_terminal_p ())
+  if (*cmd != '\0' && from_tty && input_interactive_p (current_ui))
     gdb_add_history (cmd);
 
   /* Save into global buffer if appropriate.  */
@@ -772,8 +772,7 @@ command_line_handler (char *rl)
   struct ui *ui = current_ui;
   char *cmd;
 
-  cmd = handle_line_of_input (line_buffer, rl, ui->instream == stdin,
-			      "prompt");
+  cmd = handle_line_of_input (line_buffer, rl, 1, "prompt");
   if (cmd == (char *) EOF)
     {
       /* stdin closed.  The connection with the terminal is gone.
@@ -781,7 +780,7 @@ command_line_handler (char *rl)
 	 hung up but GDB is still alive.  In such a case, we just quit
 	 gdb killing the inferior program too.  */
       printf_unfiltered ("quit\n");
-      execute_command ("quit", stdin == ui->instream);
+      execute_command ("quit", 1);
     }
   else if (cmd == NULL)
     {
@@ -838,7 +837,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
     {
       /* Read from stdin if we are executing a user defined command.
          This is the right thing for prompt_for_continue, at least.  */
-      c = fgetc (ui->instream ? ui->instream : stdin);
+      c = fgetc (ui->instream != NULL ? ui->instream : ui->stdin_stream);
 
       if (c == EOF)
 	{
@@ -1086,7 +1085,7 @@ interruptible_select (int n,
 static void
 async_sigterm_handler (gdb_client_data arg)
 {
-  quit_force (NULL, stdin == current_ui->instream);
+  quit_force (NULL, 0);
 }
 
 /* See defs.h.  */
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 4c80dbd..4cbcd5c 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -142,24 +142,6 @@ enum gdb_has_a_terminal_flag_enum
   }
 gdb_has_a_terminal_flag = have_not_checked;
 
-/* The value of the "interactive-mode" setting.  */
-static enum auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO;
-
-/* Implement the "show interactive-mode" option.  */
-
-static void
-show_interactive_mode (struct ui_file *file, int from_tty,
-                       struct cmd_list_element *c,
-                       const char *value)
-{
-  if (interactive_mode == AUTO_BOOLEAN_AUTO)
-    fprintf_filtered (file, "Debugger's interactive mode "
-		            "is %s (currently %s).\n",
-                      value, gdb_has_a_terminal () ? "on" : "off");
-  else
-    fprintf_filtered (file, "Debugger's interactive mode is %s.\n", value);
-}
-
 /* Set the initial tty state that is to be inherited by new inferiors.  */
 
 void
@@ -172,9 +154,6 @@ set_initial_gdb_ttystate (void)
 int
 gdb_has_a_terminal (void)
 {
-  if (interactive_mode != AUTO_BOOLEAN_AUTO)
-    return interactive_mode == AUTO_BOOLEAN_TRUE;
-
   switch (gdb_has_a_terminal_flag)
     {
     case yes:
@@ -899,20 +878,6 @@ _initialize_inflow (void)
   add_info ("terminal", term_info,
 	    _("Print inferior's saved terminal status."));
 
-  add_setshow_auto_boolean_cmd ("interactive-mode", class_support,
-                                &interactive_mode, _("\
-Set whether GDB's standard input is a terminal."), _("\
-Show whether GDB's standard input is a terminal."), _("\
-If on, GDB assumes that standard input is a terminal.  In practice, it\n\
-means that GDB should wait for the user to answer queries associated to\n\
-commands entered at the command prompt.  If off, GDB assumes that standard\n\
-input is not a terminal, and uses the default answer to all queries.\n\
-If auto (the default), determine which mode to use based on the standard\n\
-input settings."),
-                        NULL,
-                        show_interactive_mode,
-                        &setlist, &showlist);
-
   terminal_is_ours = 1;
 
   /* OK, figure out whether we have job control.  If neither termios nor
diff --git a/gdb/main.c b/gdb/main.c
index 8c9d563..6475ce6 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -334,7 +334,7 @@ captured_command_loop (void *data)
      error) we try to quit.  If the quit is aborted, catch_errors()
      which called this catch the signal and restart the command
      loop.  */
-  quit_command (NULL, ui->instream == stdin);
+  quit_command (NULL, ui->instream == ui->stdin_stream);
   return 1;
 }
 
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index e9dfe8e..b18d034 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -285,7 +285,7 @@ mi_execute_command_wrapper (const char *cmd)
 {
   struct ui *ui = current_ui;
 
-  mi_execute_command (cmd, stdin == ui->instream);
+  mi_execute_command (cmd, ui->instream == ui->stdin_stream);
 }
 
 /* Observer for the synchronous_command_done notification.  */
diff --git a/gdb/top.c b/gdb/top.c
index 5883875..7506c45 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -259,12 +259,15 @@ new_ui (FILE *instream, FILE *outstream, FILE *errstream)
   ui = XCNEW (struct ui);
 
   ui->num = ++highest_ui_num;
+  ui->stdin_stream = instream;
   ui->instream = instream;
   ui->outstream = outstream;
   ui->errstream = errstream;
 
   ui->input_fd = fileno (ui->instream);
 
+  ui->input_interactive_p = ISATTY (ui->instream);
+
   ui->m_gdb_stdin = stdio_fileopen (ui->instream);
   ui->m_gdb_stdout = stdio_fileopen (ui->outstream);
   ui->m_gdb_stderr = stderr_fileopen (ui->errstream);
@@ -646,7 +649,7 @@ dont_repeat (void)
   /* If we aren't reading from standard input, we are saving the last
      thing read from stdin in line and don't want to delete it.  Null
      lines won't repeat here in any case.  */
-  if (ui->instream == stdin)
+  if (ui->instream == ui->stdin_stream)
     *saved_command_line = 0;
 }
 
@@ -1108,7 +1111,7 @@ gdb_safe_append_history (void)
 
    NULL is returned for end of file.
 
-   *If* the instream == stdin & stdin is a terminal, the line read is
+   *If* input is from an interactive stream (stdin), the line read is
    copied into the global 'saved_command_line' so that it can be
    repeated.
 
@@ -1123,12 +1126,13 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
   struct ui *ui = current_ui;
   const char *prompt = prompt_arg;
   char *cmd;
+  int from_tty = ui->instream == ui->stdin_stream;
 
   /* The annotation suffix must be non-NULL.  */
   if (annotation_suffix == NULL)
     annotation_suffix = "";
 
-  if (annotation_level > 1 && ui->instream == stdin)
+  if (from_tty && annotation_level > 1)
     {
       char *local_prompt;
 
@@ -1174,7 +1178,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
       if (source_file_name != NULL)
 	++source_line_number;
 
-      if (annotation_level > 1 && ui->instream == stdin)
+      if (from_tty && annotation_level > 1)
 	{
 	  puts_unfiltered ("\n\032\032pre-");
 	  puts_unfiltered (annotation_suffix);
@@ -1182,11 +1186,15 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 	}
 
       /* Don't use fancy stuff if not talking to stdin.  */
-      if (deprecated_readline_hook && input_from_terminal_p ())
+      if (deprecated_readline_hook
+	  && from_tty
+	  && input_interactive_p (current_ui))
 	{
 	  rl = (*deprecated_readline_hook) (prompt);
 	}
-      else if (command_editing_p && input_from_terminal_p ())
+      else if (command_editing_p
+	       && from_tty
+	       && input_interactive_p (current_ui))
 	{
 	  rl = gdb_readline_wrapper (prompt);
 	}
@@ -1561,9 +1569,25 @@ quit_force (char *args, int from_tty)
   /* Save the history information if it is appropriate to do so.  */
   TRY
     {
-      if (write_history_p && history_filename
-	  && input_from_terminal_p ())
-	gdb_safe_append_history ();
+      if (write_history_p && history_filename)
+	{
+	  struct ui *ui;
+	  int save = 0;
+
+	  /* History is currently shared between all UIs.  If there's
+	     any UI with a terminal, save history.  */
+	  ALL_UIS (ui)
+	    {
+	      if (input_interactive_p (ui))
+		{
+		  save = 1;
+		  break;
+		}
+	    }
+
+	  if (save)
+	    gdb_safe_append_history ();
+	}
     }
   CATCH (ex, RETURN_MASK_ALL)
     {
@@ -1585,27 +1609,36 @@ quit_force (char *args, int from_tty)
   exit (exit_code);
 }
 
-/* Returns whether GDB is running on a terminal and input is
-   currently coming from that terminal.  */
+/* The value of the "interactive-mode" setting.  */
+static enum auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO;
 
-int
-input_from_terminal_p (void)
+/* Implement the "show interactive-mode" option.  */
+
+static void
+show_interactive_mode (struct ui_file *file, int from_tty,
+                       struct cmd_list_element *c,
+                       const char *value)
 {
-  struct ui *ui = current_ui;
+  if (interactive_mode == AUTO_BOOLEAN_AUTO)
+    fprintf_filtered (file, "Debugger's interactive mode "
+		            "is %s (currently %s).\n",
+                      value, gdb_has_a_terminal () ? "on" : "off");
+  else
+    fprintf_filtered (file, "Debugger's interactive mode is %s.\n", value);
+}
+
+/* Returns whether GDB is running on an interactive terminal.  */
 
+int
+input_interactive_p (struct ui *ui)
+{
   if (batch_flag)
     return 0;
 
-  if (gdb_has_a_terminal () && ui->instream == stdin)
-    return 1;
-
-  /* If INSTREAM is unset, and we are not in a user command, we
-     must be in Insight.  That's like having a terminal, for our
-     purposes.  */
-  if (ui->instream == NULL && !in_user_command)
-    return 1;
+  if (interactive_mode != AUTO_BOOLEAN_AUTO)
+    return interactive_mode == AUTO_BOOLEAN_TRUE;
 
-  return 0;
+  return ui->input_interactive_p;
 }
 \f
 static void
@@ -2013,6 +2046,20 @@ When set, GDB uses the specified path to search for data files."),
                            set_gdb_datadir, show_gdb_datadir,
                            &setlist,
                            &showlist);
+
+  add_setshow_auto_boolean_cmd ("interactive-mode", class_support,
+                                &interactive_mode, _("\
+Set whether GDB's standard input is a terminal."), _("\
+Show whether GDB's standard input is a terminal."), _("\
+If on, GDB assumes that standard input is a terminal.  In practice, it\n\
+means that GDB should wait for the user to answer queries associated to\n\
+commands entered at the command prompt.  If off, GDB assumes that standard\n\
+input is not a terminal, and uses the default answer to all queries.\n\
+If auto (the default), determine which mode to use based on the standard\n\
+input settings."),
+                        NULL,
+                        show_interactive_mode,
+                        &setlist, &showlist);
 }
 
 void
diff --git a/gdb/top.h b/gdb/top.h
index a0fa391..cf94ee4 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -98,6 +98,9 @@ struct ui
      currently active.  */
   int secondary_prompt_depth;
 
+  /* The UI's stdin.  Set to stdin for the main UI.  */
+  FILE *stdin_stream;
+
   /* stdio stream that command input is being read from.  Set to stdin
      normally.  Set by source_command to the file we are sourcing.
      Set to NULL if we are executing a user-defined command or
@@ -112,6 +115,11 @@ struct ui
      it with the event loop.  */
   int input_fd;
 
+  /* Whether ISATTY returns true on input_fd.  Cached here because
+     quit_force needs to know this _after_ input_fd might be
+     closed.  */
+  int input_interactive_p;
+
   /* See enum prompt_state's description.  */
   enum prompt_state prompt_state;
 
diff --git a/gdb/utils.c b/gdb/utils.c
index 78d2e98..c70e99c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1052,7 +1052,7 @@ quit (void)
   if (sync_quit_force_run)
     {
       sync_quit_force_run = 0;
-      quit_force (NULL, stdin == ui->instream);
+      quit_force (NULL, 0);
     }
 
 #ifdef __MSDOS__
@@ -1271,7 +1271,8 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
      question we're asking, and then answer the default automatically.  This
      way, important error messages don't get lost when talking to GDB
      over a pipe.  */
-  if (! input_from_terminal_p ())
+  if (current_ui->instream != current_ui->stdin_stream
+      || !input_interactive_p (current_ui))
     {
       target_terminal_ours_for_output ();
       wrap_here ("");
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 12/34] Delete def_uiout
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (17 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 04/34] Make gdb_stdout&co be per UI Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-06 12:43 ` [PATCH v3 10/34] Make input_fd be per UI Pedro Alves
                   ` (16 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

Currently, current_uiout starts out pointing to def_uiout, a dummy
ui_out implementation.

Since we create a replacement uiout early on as soon as we create the
interpreter, we never actually use def_uiout.  So this patch removes
it.

The proof that it works is that starting with current_uiout set to
NULL does not crash.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* ui-out.c (default_ui_out_impl): Delete.
	(def_uiout): Delete.
	(current_uiout): Set to NULL.
	(default_table_begin, default_table_body, default_table_end)
	(default_table_header, default_begin, default_end)
	(default_field_int, default_field_skip, default_field_string)
	(default_field_fmt, default_spaces, default_text, default_message)
	(default_wrap_hint, default_flush, default_data_destroy): Delete.
---
 gdb/ui-out.c | 181 +----------------------------------------------------------
 1 file changed, 1 insertion(+), 180 deletions(-)

diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index e5a2bf1..4ea571b 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -147,84 +147,10 @@ pop_level (struct ui_out *uiout,
   return uiout->level + 1;
 }
 
-
-/* These are the default implementation functions.  */
-
-static void default_table_begin (struct ui_out *uiout, int nbrofcols,
-				 int nr_rows, const char *tblid);
-static void default_table_body (struct ui_out *uiout);
-static void default_table_end (struct ui_out *uiout);
-static void default_table_header (struct ui_out *uiout, int width,
-				  enum ui_align alig, const char *col_name,
-				  const char *colhdr);
-static void default_begin (struct ui_out *uiout,
-			   enum ui_out_type type,
-			   int level, const char *id);
-static void default_end (struct ui_out *uiout,
-			 enum ui_out_type type,
-			 int level);
-static void default_field_int (struct ui_out *uiout, int fldno, int width,
-			       enum ui_align alig,
-			       const char *fldname,
-			       int value);
-static void default_field_skip (struct ui_out *uiout, int fldno, int width,
-				enum ui_align alig,
-				const char *fldname);
-static void default_field_string (struct ui_out *uiout, int fldno, int width,
-				  enum ui_align align,
-				  const char *fldname,
-				  const char *string);
-static void default_field_fmt (struct ui_out *uiout, int fldno,
-			       int width, enum ui_align align,
-			       const char *fldname,
-			       const char *format,
-			       va_list args) ATTRIBUTE_PRINTF (6, 0);
-static void default_spaces (struct ui_out *uiout, int numspaces);
-static void default_text (struct ui_out *uiout, const char *string);
-static void default_message (struct ui_out *uiout, int verbosity,
-			     const char *format,
-			     va_list args) ATTRIBUTE_PRINTF (3, 0);
-static void default_wrap_hint (struct ui_out *uiout, char *identstring);
-static void default_flush (struct ui_out *uiout);
-static void default_data_destroy (struct ui_out *uiout);
-
-/* This is the default ui-out implementation functions vector.  */
-
-const struct ui_out_impl default_ui_out_impl =
-{
-  default_table_begin,
-  default_table_body,
-  default_table_end,
-  default_table_header,
-  default_begin,
-  default_end,
-  default_field_int,
-  default_field_skip,
-  default_field_string,
-  default_field_fmt,
-  default_spaces,
-  default_text,
-  default_message,
-  default_wrap_hint,
-  default_flush,
-  NULL, /* redirect */
-  default_data_destroy,
-  0, /* Does not need MI hacks.  */
-};
-
-/* The default ui_out */
-
-struct ui_out def_uiout =
-{
-  0,				/* flags */
-  &default_ui_out_impl,		/* impl */
-};
-
-/* Pointer to current ui_out */
 /* FIXME: This should not be a global, but something passed down from main.c
    or top.c.  */
 
-struct ui_out *current_uiout = &def_uiout;
+struct ui_out *current_uiout = NULL;
 
 /* These are the interfaces to implementation functions.  */
 
@@ -652,111 +578,6 @@ ui_out_is_mi_like_p (struct ui_out *uiout)
   return uiout->impl->is_mi_like_p;
 }
 
-/* Default gdb-out hook functions.  */
-
-static void
-default_table_begin (struct ui_out *uiout, int nbrofcols,
-		     int nr_rows,
-		     const char *tblid)
-{
-}
-
-static void
-default_table_body (struct ui_out *uiout)
-{
-}
-
-static void
-default_table_end (struct ui_out *uiout)
-{
-}
-
-static void
-default_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
-		      const char *col_name,
-		      const char *colhdr)
-{
-}
-
-static void
-default_begin (struct ui_out *uiout,
-	       enum ui_out_type type,
-	       int level,
-	       const char *id)
-{
-}
-
-static void
-default_end (struct ui_out *uiout,
-	     enum ui_out_type type,
-	     int level)
-{
-}
-
-static void
-default_field_int (struct ui_out *uiout, int fldno, int width,
-		   enum ui_align align,
-		   const char *fldname, int value)
-{
-}
-
-static void
-default_field_skip (struct ui_out *uiout, int fldno, int width,
-		    enum ui_align align, const char *fldname)
-{
-}
-
-static void
-default_field_string (struct ui_out *uiout,
-		      int fldno,
-		      int width,
-		      enum ui_align align,
-		      const char *fldname,
-		      const char *string)
-{
-}
-
-static void
-default_field_fmt (struct ui_out *uiout, int fldno, int width,
-		   enum ui_align align,
-		   const char *fldname,
-		   const char *format,
-		   va_list args)
-{
-}
-
-static void
-default_spaces (struct ui_out *uiout, int numspaces)
-{
-}
-
-static void
-default_text (struct ui_out *uiout, const char *string)
-{
-}
-
-static void
-default_message (struct ui_out *uiout, int verbosity,
-		 const char *format,
-		 va_list args)
-{
-}
-
-static void
-default_wrap_hint (struct ui_out *uiout, char *identstring)
-{
-}
-
-static void
-default_flush (struct ui_out *uiout)
-{
-}
-
-static void
-default_data_destroy (struct ui_out *uiout)
-{
-}
-
 /* Interface to the implementation functions.  */
 
 void
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 05/34] Make the interpreters be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (21 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 28/34] Make stdin be per UI Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-18 17:51   ` Simon Marchi
  2016-05-06 12:43 ` [PATCH v3 17/34] Introduce display_mi_prompt Pedro Alves
                   ` (12 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

Make each UI have its own interpreter list, top level interpreter,
current interpreter, etc.  The "interpreter_async" global is not
really specific to an struct interp (it crosses interpreter-exec ...),
so I moved it to "struct ui" directly, while the other globals were
left hidden in interps.c, opaque to the rest of GDB.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* breakpoint.c (bpstat_do_actions_1): Access the current UI's
	async field instead of the interpreter_async global.
	* cli/cli-script.c (execute_user_command, while_command)
	(if_command, script_from_file): Likewise.
	* compile/compile.c: Include top.h instead of interps.h.
	(compile_file_command, compile_code_command)
	(compile_print_command): Access the current UI's async field
	instead of the interpreter_async global.
	* guile/guile.c: Include top.h instead of interps.h.
	(guile_repl_command, guile_command, gdbscm_execute_gdb_command):
	Access the current UI's async field instead of the
	interpreter_async global.
	* guile/scm-ports.c: Include top.h instead of interps.h.
	(ioscm_with_output_to_port_worker): Access the current UI's async
	field instead of the interpreter_async global.
	* inf-loop.c (inferior_event_handler): Likewise.
	* infcall.c (run_inferior_call): Likewise.
	* infrun.c (reinstall_readline_callback_handler_cleanup)
	(fetch_inferior_event): Likewise.
	* interps.c (interpreter_async): Delete.
	(struct ui_interp_info): New.
	(get_current_interp_info): New function.
	(interp_list, current_interpreter, top_level_interpreter_ptr):
	Delete.
	(interp_add, interp_set, interp_lookup, interp_ui_out)
	(current_interp_set_logging, interp_set_temp)
	(current_interp_named_p): Adjust to per-UI interpreters.
	(command_interpreter): Delete.
	(command_interp, current_interp_command_loop, interp_quiet_p)
	(interp_exec, interpreter_exec_cmd, interpreter_completer)
	(top_level_interpretertop_level_interpreter)
	(top_level_interpreter_data): Adjust to per-UI interpreters.
	* interps.h (interpreter_async): Delete.
	* main.c (captured_command_loop): Access the current UI's async
	field instead of the interpreter_async global.
	* python/python.c (python_interactive_command, python_command)
	(execute_gdb_command): Likewise.
	* top.c (maybe_wait_sync_command_done, execute_command_to_string):
	Access the current UI's async field instead of the
	interpreter_async global.
	* top.h (struct tl_interp_info): Forward declare.
	(struct ui) <interp_info, async>: New fields.
---
 gdb/breakpoint.c      |   2 +-
 gdb/cli/cli-script.c  |  16 +++---
 gdb/compile/compile.c |  14 ++---
 gdb/guile/guile.c     |  14 ++---
 gdb/guile/scm-ports.c |   6 +-
 gdb/inf-loop.c        |   2 +-
 gdb/infcall.c         |   6 +-
 gdb/infrun.c          |   4 +-
 gdb/interps.c         | 151 +++++++++++++++++++++++++++++++-------------------
 gdb/interps.h         |   9 ---
 gdb/main.c            |   2 +-
 gdb/python/python.c   |  12 ++--
 gdb/top.c             |   6 +-
 gdb/top.h             |  15 +++++
 14 files changed, 152 insertions(+), 107 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a39a15c..a28e956 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4733,7 +4733,7 @@ bpstat_do_actions_1 (bpstat *bsp)
 
       if (breakpoint_proceeded)
 	{
-	  if (interpreter_async)
+	  if (current_ui->async)
 	    /* If we are in async mode, then the target might be still
 	       running, not stopped at any breakpoint, so nothing for
 	       us to do here -- just return to the event loop.  */
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 7302330..5fc01b3 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -379,8 +379,8 @@ execute_user_command (struct cmd_list_element *c, char *args)
      not confused with Insight.  */
   in_user_command = 1;
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   command_nest_depth++;
   while (cmdlines)
@@ -661,8 +661,8 @@ while_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
-  old_chain = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  old_chain = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   execute_control_command_untraced (command);
   free_command_lines (&command);
@@ -685,8 +685,8 @@ if_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
-  old_chain = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  old_chain = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   execute_control_command_untraced (command);
   free_command_lines (&command);
@@ -1688,8 +1688,8 @@ script_from_file (FILE *stream, const char *file)
   source_line_number = 0;
   source_file_name = file;
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   {
 
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 77b4137..0c4a738 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -18,7 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "interps.h"
+#include "top.h"
 #include "ui-out.h"
 #include "command.h"
 #include "cli/cli-script.h"
@@ -91,8 +91,8 @@ compile_file_command (char *arg, int from_tty)
   char *buffer;
   struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   /* Check the user did not just <enter> after command.  */
   if (arg == NULL)
@@ -133,8 +133,8 @@ compile_code_command (char *arg, int from_tty)
   struct cleanup *cleanup;
   enum compile_i_scope_types scope = COMPILE_I_SIMPLE_SCOPE;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   if (arg != NULL && check_raw_argument (&arg))
     {
@@ -187,8 +187,8 @@ compile_print_command (char *arg_param, int from_tty)
   enum compile_i_scope_types scope = COMPILE_I_PRINT_ADDRESS_SCOPE;
   struct format_data fmt;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   /* Passing &FMT as SCOPE_DATA is safe as do_module_cleanup will not
      touch the stale pointer if compile_object_run has already quit.  */
diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c
index b010e59..117561d 100644
--- a/gdb/guile/guile.c
+++ b/gdb/guile/guile.c
@@ -27,7 +27,7 @@
 #include "cli/cli-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
-#include "interps.h"
+#include "top.h"
 #include "extension-priv.h"
 #include "utils.h"
 #include "version.h"
@@ -165,8 +165,8 @@ guile_repl_command (char *arg, int from_tty)
 {
   struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
 
@@ -198,8 +198,8 @@ guile_command (char *arg, int from_tty)
 {
   struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
 
@@ -328,8 +328,8 @@ gdbscm_execute_gdb_command (SCM command_scm, SCM rest)
     {
       struct cleanup *inner_cleanups;
 
-      inner_cleanups = make_cleanup_restore_integer (&interpreter_async);
-      interpreter_async = 0;
+      inner_cleanups = make_cleanup_restore_integer (&current_ui->async);
+      current_ui->async = 0;
 
       prevent_dont_repeat ();
       if (to_string)
diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
index b0f576e..5559475 100644
--- a/gdb/guile/scm-ports.c
+++ b/gdb/guile/scm-ports.c
@@ -23,7 +23,7 @@
 
 #include "defs.h"
 #include "gdb_select.h"
-#include "interps.h"
+#include "top.h"
 #include "target.h"
 #include "guile-internal.h"
 
@@ -517,8 +517,8 @@ ioscm_with_output_to_port_worker (SCM port, SCM thunk, enum oport oport,
 
   cleanups = set_batch_flag_and_make_cleanup_restore_page_info ();
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   port_file = ioscm_file_port_new (port);
 
diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c
index 2591ae9..d006df8 100644
--- a/gdb/inf-loop.c
+++ b/gdb/inf-loop.c
@@ -61,7 +61,7 @@ inferior_event_handler (enum inferior_event_type event_type,
 
       /* When running a command list (from a user command, say), these
 	 are only run when the command list is all done.  */
-      if (interpreter_async)
+      if (current_ui->async)
 	{
 	  check_frame_language_change ();
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 77cd931..11f5aba 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -560,13 +560,13 @@ run_inferior_call (struct call_thread_fsm *sm,
   ptid_t call_thread_ptid = call_thread->ptid;
   int saved_sync_execution = sync_execution;
   int was_running = call_thread->state == THREAD_RUNNING;
-  int saved_interpreter_async = interpreter_async;
+  int saved_ui_async = current_ui->async;
 
   /* Infcalls run synchronously, in the foreground.  */
   sync_execution = 1;
   /* So that we don't print the prompt prematurely in
      fetch_inferior_event.  */
-  interpreter_async = 0;
+  current_ui->async = 0;
 
   call_thread->control.in_infcall = 1;
 
@@ -601,7 +601,7 @@ run_inferior_call (struct call_thread_fsm *sm,
      again here.  In other cases, stdin will be re-enabled by
      inferior_event_handler, when an exception is thrown.  */
   sync_execution = saved_sync_execution;
-  interpreter_async = saved_interpreter_async;
+  current_ui->async = saved_ui_async;
 
   /* At this point the current thread may have changed.  Refresh
      CALL_THREAD as it could be invalid if its thread has exited.  */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index cfb1d06..ba7144a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3806,7 +3806,7 @@ wait_for_inferior (void)
 static void
 reinstall_readline_callback_handler_cleanup (void *arg)
 {
-  if (!interpreter_async)
+  if (!current_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,
@@ -3993,7 +3993,7 @@ fetch_inferior_event (void *client_data)
   /* 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 (interpreter_async && was_sync && !sync_execution)
+  if (current_ui->async && was_sync && !sync_execution)
     observer_notify_sync_execution_done ();
 
   if (cmd_done
diff --git a/gdb/interps.c b/gdb/interps.c
index b188d08..7f57132 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -39,11 +39,31 @@
 #include "top.h"		/* For command_loop.  */
 #include "continuations.h"
 
-/* True if the current interpreter in is async mode.  See interps.h
-   for more details.  This starts out disabled, until all the explicit
-   command line arguments (e.g., `gdb -ex "start" -ex "next"') are
-   processed.  */
-int interpreter_async = 0;
+/* Each UI has its own independent set of interpreters.  */
+
+struct ui_interp_info
+{
+  /* Each top level has its own independent set of interpreters.  */
+  struct interp *interp_list;
+  struct interp *current_interpreter;
+  struct interp *top_level_interpreter_ptr;
+
+  /* The interpreter that is active while `interp_exec' is active, NULL
+     at all other times.  */
+  struct interp *command_interpreter;
+};
+
+/* Get the current UI's ui_interp_info object.  Never returns NULL.  */
+
+static struct ui_interp_info *
+get_current_interp_info (void)
+{
+  struct ui *ui = current_ui;
+
+  if (ui->interp_info == NULL)
+    ui->interp_info = XCNEW (struct ui_interp_info);
+  return ui->interp_info;
+}
 
 struct interp
 {
@@ -71,12 +91,6 @@ struct interp
 
 void _initialize_interpreter (void);
 
-/* Variables local to this file: */
-
-static struct interp *interp_list = NULL;
-static struct interp *current_interpreter = NULL;
-static struct interp *top_level_interpreter_ptr = NULL;
-
 /* interp_new - This allocates space for a new interpreter,
    fills the fields from the inputs, and returns a pointer to the
    interpreter.  */
@@ -104,10 +118,12 @@ interp_new (const char *name, const struct interp_procs *procs)
 void
 interp_add (struct interp *interp)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
   gdb_assert (interp_lookup (interp->name) == NULL);
 
-  interp->next = interp_list;
-  interp_list = interp;
+  interp->next = ui_interp->interp_list;
+  ui_interp->interp_list = interp;
 }
 
 /* This sets the current interpreter to be INTERP.  If INTERP has not
@@ -127,24 +143,24 @@ interp_add (struct interp *interp)
 int
 interp_set (struct interp *interp, int top_level)
 {
-  struct interp *old_interp = current_interpreter;
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *old_interp = ui_interp->current_interpreter;
   int first_time = 0;
   char buffer[64];
 
   /* If we already have an interpreter, then trying to
      set top level interpreter is kinda pointless.  */
-  gdb_assert (!top_level || !current_interpreter);
-  gdb_assert (!top_level || !top_level_interpreter_ptr);
+  gdb_assert (!top_level || !ui_interp->current_interpreter);
+  gdb_assert (!top_level || !ui_interp->top_level_interpreter_ptr);
 
-  if (current_interpreter != NULL)
+  if (old_interp != NULL)
     {
       ui_out_flush (current_uiout);
-      if (current_interpreter->procs->suspend_proc
-	  && !current_interpreter->procs->suspend_proc (current_interpreter->
-							data))
+      if (old_interp->procs->suspend_proc
+	  && !old_interp->procs->suspend_proc (old_interp->data))
 	{
 	  error (_("Could not suspend interpreter \"%s\"."),
-		 current_interpreter->name);
+		 old_interp->name);
 	}
     }
   else
@@ -152,18 +168,18 @@ interp_set (struct interp *interp, int top_level)
       first_time = 1;
     }
 
-  current_interpreter = interp;
+  ui_interp->current_interpreter = interp;
   if (top_level)
-    top_level_interpreter_ptr = interp;
+    ui_interp->top_level_interpreter_ptr = interp;
 
   /* We use interpreter_p for the "set interpreter" variable, so we need
      to make sure we have a malloc'ed copy for the set command to free.  */
   if (interpreter_p != NULL
-      && strcmp (current_interpreter->name, interpreter_p) != 0)
+      && strcmp (interp->name, interpreter_p) != 0)
     {
       xfree (interpreter_p);
 
-      interpreter_p = xstrdup (current_interpreter->name);
+      interpreter_p = xstrdup (interp->name);
     }
 
   /* Run the init proc.  If it fails, try to restore the old interp.  */
@@ -209,12 +225,15 @@ interp_set (struct interp *interp, int top_level)
 struct interp *
 interp_lookup (const char *name)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *interp;
 
   if (name == NULL || strlen (name) == 0)
     return NULL;
 
-  for (interp = interp_list; interp != NULL; interp = interp->next)
+  for (interp = ui_interp->interp_list;
+       interp != NULL;
+       interp = interp->next)
     {
       if (strcmp (interp->name, name) == 0)
 	return interp;
@@ -228,34 +247,37 @@ interp_lookup (const char *name)
 struct ui_out *
 interp_ui_out (struct interp *interp)
 {
-  if (interp != NULL)
-    return interp->procs->ui_out_proc (interp);
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
 
-  return current_interpreter->procs->ui_out_proc (current_interpreter);
+  if (interp == NULL)
+    interp = ui_interp->current_interpreter;
+  return interp->procs->ui_out_proc (interp);
 }
 
 int
 current_interp_set_logging (int start_log, struct ui_file *out,
 			    struct ui_file *logfile)
 {
-  if (current_interpreter == NULL
-      || current_interpreter->procs->set_logging_proc == NULL)
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *interp = ui_interp->current_interpreter;
+
+  if (interp == NULL
+      || interp->procs->set_logging_proc == NULL)
     return 0;
 
-  return current_interpreter->procs->set_logging_proc (current_interpreter,
-						       start_log, out,
-						       logfile);
+  return interp->procs->set_logging_proc (interp, start_log, out, logfile);
 }
 
 /* Temporarily overrides the current interpreter.  */
 struct interp *
 interp_set_temp (const char *name)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *interp = interp_lookup (name);
-  struct interp *old_interp = current_interpreter;
+  struct interp *old_interp = ui_interp->current_interpreter;
 
   if (interp)
-    current_interpreter = interp;
+    ui_interp->current_interpreter = interp;
   return old_interp;
 }
 
@@ -279,16 +301,15 @@ interp_name (struct interp *interp)
 int
 current_interp_named_p (const char *interp_name)
 {
-  if (current_interpreter)
-    return (strcmp (current_interpreter->name, interp_name) == 0);
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *interp = ui_interp->current_interpreter;
+
+  if (interp != NULL)
+    return (strcmp (interp->name, interp_name) == 0);
 
   return 0;
 }
 
-/* The interpreter that is active while `interp_exec' is active, NULL
-   at all other times.  */
-static struct interp *command_interpreter;
-
 /* The interpreter that was active when a command was executed.
    Normally that'd always be CURRENT_INTERPRETER, except that MI's
    -interpreter-exec command doesn't actually flip the current
@@ -302,28 +323,35 @@ static struct interp *command_interpreter;
 struct interp *
 command_interp (void)
 {
-  if (command_interpreter != NULL)
-    return command_interpreter;
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
+  if (ui_interp->command_interpreter != NULL)
+    return ui_interp->command_interpreter;
   else
-    return current_interpreter;
+    return ui_interp->current_interpreter;
 }
 
 /* Run the current command interpreter's main loop.  */
 void
 current_interp_command_loop (void)
 {
-  gdb_assert (current_interpreter != NULL);
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *interp = ui_interp->current_interpreter;
+
+  gdb_assert (ui_interp->current_interpreter != NULL);
 
-  current_interpreter->procs->command_loop_proc (current_interpreter->data);
+  interp->procs->command_loop_proc (interp->data);
 }
 
 int
 interp_quiet_p (struct interp *interp)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
   if (interp != NULL)
     return interp->quiet_p;
   else
-    return current_interpreter->quiet_p;
+    return ui_interp->current_interpreter->quiet_p;
 }
 
 static int
@@ -341,18 +369,20 @@ interp_set_quiet (struct interp *interp, int quiet)
 struct gdb_exception
 interp_exec (struct interp *interp, const char *command_str)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
   struct gdb_exception ex;
   struct interp *save_command_interp;
 
   gdb_assert (interp->procs->exec_proc != NULL);
 
   /* See `command_interp' for why we do this.  */
-  save_command_interp = command_interpreter;
-  command_interpreter = interp;
+  save_command_interp = ui_interp->command_interpreter;
+  ui_interp->command_interpreter = interp;
 
   ex = interp->procs->exec_proc (interp->data, command_str);
 
-  command_interpreter = save_command_interp;
+  ui_interp->command_interpreter = save_command_interp;
 
   return ex;
 }
@@ -379,6 +409,7 @@ clear_interpreter_hooks (void)
 static void
 interpreter_exec_cmd (char *args, int from_tty)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *old_interp, *interp_to_use;
   char **prules = NULL;
   char **trule = NULL;
@@ -400,7 +431,7 @@ interpreter_exec_cmd (char *args, int from_tty)
   if (nrules < 2)
     error (_("usage: interpreter-exec <interpreter> [ <command> ... ]"));
 
-  old_interp = current_interpreter;
+  old_interp = ui_interp->current_interpreter;
 
   interp_to_use = interp_lookup (prules[0]);
   if (interp_to_use == NULL)
@@ -438,12 +469,15 @@ static VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   int textlen;
   VEC (char_ptr) *matches = NULL;
   struct interp *interp;
 
   textlen = strlen (text);
-  for (interp = interp_list; interp != NULL; interp = interp->next)
+  for (interp = ui_interp->interp_list;
+       interp != NULL;
+       interp = interp->next)
     {
       if (strncmp (interp->name, text, textlen) == 0)
 	{
@@ -474,14 +508,19 @@ interpreter_completer (struct cmd_list_element *ignore,
 struct interp *
 top_level_interpreter (void)
 {
-  return top_level_interpreter_ptr;  
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
+  return ui_interp->top_level_interpreter_ptr;
 }
 
 void *
 top_level_interpreter_data (void)
 {
-  gdb_assert (top_level_interpreter_ptr);
-  return top_level_interpreter_ptr->data;  
+  struct interp *interp;
+
+  interp = top_level_interpreter ();
+  gdb_assert (interp != NULL);
+  return interp->data;
 }
 
 /* This just adds the "interpreter-exec" command.  */
diff --git a/gdb/interps.h b/gdb/interps.h
index 19cd1c2..f0badc5 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -93,15 +93,6 @@ extern struct interp *top_level_interpreter (void);
 
 extern struct interp *command_interp (void);
 
-/* True if the current interpreter is in async mode, false if in sync
-   mode.  If in sync mode, running a synchronous execution command
-   (with execute_command, e.g, "next") will not return until the
-   command is finished.  If in async mode, then running a synchronous
-   command returns right after resuming the target.  Waiting for the
-   command's completion is later done on the top event loop (using
-   continuations).  */
-extern int interpreter_async;
-
 extern void clear_interpreter_hooks (void);
 
 /* well-known interpreters */
diff --git a/gdb/main.c b/gdb/main.c
index 03d6bbd..d84340e 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -311,7 +311,7 @@ captured_command_loop (void *data)
 {
   /* Top-level execution commands can be run in the background from
      here on.  */
-  interpreter_async = 1;
+  current_ui->async = 1;
 
   current_interp_command_loop ();
   /* FIXME: cagney/1999-11-05: A correct command_loop() implementaton
diff --git a/gdb/python/python.c b/gdb/python/python.c
index c706644..fa1c78e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -321,8 +321,8 @@ python_interactive_command (char *arg, int from_tty)
   struct cleanup *cleanup;
   int err;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
 
@@ -466,8 +466,8 @@ python_command (char *arg, int from_tty)
 
   cleanup = ensure_python_env (get_current_arch (), current_language);
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
   if (arg && *arg)
@@ -650,8 +650,8 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
       struct cleanup *cleanup = make_cleanup (xfree, copy);
       struct interp *interp;
 
-      make_cleanup_restore_integer (&interpreter_async);
-      interpreter_async = 0;
+      make_cleanup_restore_integer (&current_ui->async);
+      current_ui->async = 0;
 
       make_cleanup_restore_ui_out (&current_uiout);
       /* Use the console interpreter uiout to have the same print format
diff --git a/gdb/top.c b/gdb/top.c
index a34635b..3842f0c 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -407,7 +407,7 @@ 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 (!interpreter_async && !was_sync && sync_execution)
+  if (!current_ui->async && !was_sync && sync_execution)
     wait_sync_command_done ();
 }
 
@@ -525,8 +525,8 @@ execute_command_to_string (char *p, int from_tty)
      restoration callbacks.  */
   cleanup = set_batch_flag_and_make_cleanup_restore_page_info ();
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   str_file = mem_fileopen ();
 
diff --git a/gdb/top.h b/gdb/top.h
index d404427..f18b79e 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -23,6 +23,8 @@
 #include "buffer.h"
 #include "event-loop.h"
 
+struct tl_interp_info;
+
 /* 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
@@ -50,6 +52,19 @@ struct ui
      processing.  */
   void (*input_handler) (char *);
 
+  /* Each UI has its own independent set of interpreters.  */
+  struct ui_interp_info *interp_info;
+
+  /* True if the UI is in async mode, false if in sync mode.  If in
+     sync mode, a synchronous execution command (e.g, "next") does not
+     return until the command is finished.  If in async mode, then
+     running a synchronous command returns right after resuming the
+     target.  Waiting for the command's completion is later done on
+     the top event loop.  For the main UI, this starts out disabled,
+     until all the explicit command line arguments (e.g., `gdb -ex
+     "start" -ex "next"') are processed.  */
+  int async;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 07/34] Make the intepreters output to all UIs
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (24 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 08/34] Always run async signal handlers in the main UI Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-19 15:16   ` Simon Marchi
  2016-05-06 12:45 ` [PATCH v3 32/34] Send deleted watchpoint-scope " Pedro Alves
                   ` (9 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

When we have multiple consoles, MI channels, etc., then we need to
broadcast breakpoint hits, etc. to all UIs.  In the past, I've
adjusted most of the run control to communicate events to the
interpreters through observer notifications, so events would be
properly sent to console and MI streams, in sync and async modes.

This patch does the next logical step -- have each interpreter's
observers output interpreter-specific info to _all_ UIs.

Note that when we have multiple instances of active cli/tui
interpreters, then the cli_interp and tui_interp globals no longer
work.  This is addressed by this patch.

Also, the interpreters currently register some observers when resumed
and remove them when suspended.  If we have multiple instances of the
interpreters, and they can be suspended/resumed at different,
independent times, that no longer works.  What we instead do is always
install the observers, and then have the observers themselves know
when to do nothing.

An earlier prototype of this series did the looping over struct UIs in
common code, and then dispatched events to the interpreters through a
matching interp_on_foo method for each observer.  That turned out a
lot more complicated than the present solution, as we'd end up with
having to create a new interp method every time some interpreter
wanted to listen to some observer notification, resulting in a lot of
duplicated make-work and more coupling than desirable.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-interp.c (cli_interp): Delete.
	(as_cli_interp): New function.
	(cli_on_normal_stop, cli_on_signal_received)
	(cli_on_end_stepping_range, cli_on_signal_exited, cli_on_exited)
	(cli_on_no_history): Send output to all CLI UIs.
	(cli_on_sync_execution_done, cli_on_command_error): Skip output if
	the top level interpreter is not a CLI.
	(cli_interpreter_init): Don't set cli_interp or install observers
	here.
	(_initialize_cli_interp): Install observers here.
	* event-top.c (main_ui_, ui_list): New globals.
	(current_ui): Point to main_ui_.
	(restore_ui_cleanup, switch_thru_all_uis_init)
	(switch_thru_all_uis_cond, switch_thru_all_uis_next): New
	functions.
	* mi/mi-interp.c (as_mi_interp): New function.
	(mi_interpreter_init): Don't install observers here.
	(mi_on_sync_execution_done): Skip output if the top level
	interpreter is not a MI.
	(mi_new_thread, mi_thread_exit, mi_record_changed)
	(mi_inferior_added, mi_inferior_appeared, mi_inferior_exit)
	(mi_inferior_removed): Send output to all MI UIs.
	(find_mi_interpreter, mi_interp_data): Delete.
	(find_mi_interp): New function.
	(mi_on_signal_received, mi_on_end_stepping_range)
	(mi_on_signal_exited, mi_on_exited, mi_on_no_history): Send output
	to all MI UIs.
	(mi_on_normal_stop): Rename to ...
	(mi_on_normal_stop_1): ... this.
	(mi_on_normal_stop): Reimplement, sending output to all MI UIs.
	(mi_traceframe_changed, mi_tsv_created, mi_tsv_deleted)
	(mi_tsv_modified, mi_breakpoint_created, mi_breakpoint_deleted)
	(mi_breakpoint_modified, mi_output_running_pid): Send output to
	all MI UIs.
	(mi_on_resume): Rename to ...
	(mi_on_resume_1): ... this.  Don't handle infcalls here.
	(mi_on_resume): Reimplement, sending output to all MI UIs.
	(mi_solib_loaded, mi_solib_unloaded, mi_command_param_changed)
	(mi_memory_changed): Send output to all MI UIs.
	(report_initial_inferior): Install observers here.
	* top.h (struct ui) <next>: New field.
	(ui_list): Declare.
	(struct switch_thru_all_uis): New.
	(switch_thru_all_uis_init, switch_thru_all_uis_cond)
	(switch_thru_all_uis_next): Declare.
	(SWITCH_THRU_ALL_UIS): New macro.
	* tui/tui-interp.c (tui_interp): Delete global.
	(as_tui_interp): New function.
	(tui_on_normal_stop, tui_on_signal_received)
	(tui_on_end_stepping_range, tui_on_signal_exited, tui_on_exited)
	(tui_on_no_history): Send output to all TUI UIs.
	(tui_on_sync_execution_done, tui_on_command_error): Skip output if
	the top level interpreter is not a TUI.
	(tui_init): Don't set tui_interp or install observers here.
	(_initialize_tui_interp): Install observers here.
---
 gdb/cli/cli-interp.c | 127 +++++--
 gdb/event-top.c      |  51 ++-
 gdb/mi/mi-interp.c   | 919 ++++++++++++++++++++++++++++++++-------------------
 gdb/top.h            |  29 ++
 gdb/tui/tui-interp.c | 127 +++++--
 5 files changed, 841 insertions(+), 412 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index ac12a4c..cd33dd2 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -33,8 +33,16 @@ struct cli_interp
   struct ui_out *cli_uiout;
 };
 
-/* The interpreter for the console interpreter.  */
-static struct interp *cli_interp;
+/* Returns the INTERP's data cast as cli_interp if INTERP is a CLI,
+   and returns NULL otherwise.  */
+
+static struct cli_interp *
+as_cli_interp (struct interp *interp)
+{
+  if (strcmp (interp_name (interp), INTERP_CONSOLE) == 0)
+    return (struct cli_interp *) interp_data (interp);
+  return NULL;
+}
 
 /* Longjmp-safe wrapper for "execute_command".  */
 static struct gdb_exception safe_execute_command (struct ui_out *uiout,
@@ -50,10 +58,17 @@ static struct gdb_exception safe_execute_command (struct ui_out *uiout,
 static void
 cli_on_normal_stop (struct bpstats *bs, int print_frame)
 {
-  if (!interp_quiet_p (cli_interp))
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
     {
+      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+      if (cli == NULL)
+	continue;
+
       if (print_frame)
-	print_stop_event (interp_ui_out (cli_interp));
+	print_stop_event (cli->cli_uiout);
     }
 }
 
@@ -62,8 +77,17 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame)
 static void
 cli_on_signal_received (enum gdb_signal siggnal)
 {
-  if (!interp_quiet_p (cli_interp))
-    print_signal_received_reason (interp_ui_out (cli_interp), siggnal);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+      if (cli == NULL)
+	continue;
+
+      print_signal_received_reason (cli->cli_uiout, siggnal);
+    }
 }
 
 /* Observer for the end_stepping_range notification.  */
@@ -71,8 +95,17 @@ cli_on_signal_received (enum gdb_signal siggnal)
 static void
 cli_on_end_stepping_range (void)
 {
-  if (!interp_quiet_p (cli_interp))
-    print_end_stepping_range_reason (interp_ui_out (cli_interp));
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+      if (cli == NULL)
+	continue;
+
+      print_end_stepping_range_reason (cli->cli_uiout);
+    }
 }
 
 /* Observer for the signalled notification.  */
@@ -80,8 +113,17 @@ cli_on_end_stepping_range (void)
 static void
 cli_on_signal_exited (enum gdb_signal siggnal)
 {
-  if (!interp_quiet_p (cli_interp))
-    print_signal_exited_reason (interp_ui_out (cli_interp), siggnal);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+      if (cli == NULL)
+	continue;
+
+      print_signal_exited_reason (cli->cli_uiout, siggnal);
+    }
 }
 
 /* Observer for the exited notification.  */
@@ -89,8 +131,17 @@ cli_on_signal_exited (enum gdb_signal siggnal)
 static void
 cli_on_exited (int exitstatus)
 {
-  if (!interp_quiet_p (cli_interp))
-    print_exited_reason (interp_ui_out (cli_interp), exitstatus);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+      if (cli == NULL)
+	continue;
+
+      print_exited_reason (cli->cli_uiout, exitstatus);
+    }
 }
 
 /* Observer for the no_history notification.  */
@@ -98,8 +149,17 @@ cli_on_exited (int exitstatus)
 static void
 cli_on_no_history (void)
 {
-  if (!interp_quiet_p (cli_interp))
-    print_no_history_reason (interp_ui_out (cli_interp));
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+      if (cli == NULL)
+	continue;
+
+      print_no_history_reason (cli->cli_uiout);
+    }
 }
 
 /* Observer for the sync_execution_done notification.  */
@@ -107,8 +167,12 @@ cli_on_no_history (void)
 static void
 cli_on_sync_execution_done (void)
 {
-  if (!interp_quiet_p (cli_interp))
-    display_gdb_prompt (NULL);
+  struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+  if (cli == NULL)
+    return;
+
+  display_gdb_prompt (NULL);
 }
 
 /* Observer for the command_error notification.  */
@@ -116,8 +180,12 @@ cli_on_sync_execution_done (void)
 static void
 cli_on_command_error (void)
 {
-  if (!interp_quiet_p (cli_interp))
-    display_gdb_prompt (NULL);
+  struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+  if (cli == NULL)
+    return;
+
+  display_gdb_prompt (NULL);
 }
 
 /* These implement the cli out interpreter: */
@@ -125,19 +193,6 @@ cli_on_command_error (void)
 static void *
 cli_interpreter_init (struct interp *self, int top_level)
 {
-  if (top_level)
-    cli_interp = self;
-
-  /* If changing this, remember to update tui-interp.c as well.  */
-  observer_attach_normal_stop (cli_on_normal_stop);
-  observer_attach_end_stepping_range (cli_on_end_stepping_range);
-  observer_attach_signal_received (cli_on_signal_received);
-  observer_attach_signal_exited (cli_on_signal_exited);
-  observer_attach_exited (cli_on_exited);
-  observer_attach_no_history (cli_on_no_history);
-  observer_attach_sync_execution_done (cli_on_sync_execution_done);
-  observer_attach_command_error (cli_on_command_error);
-
   return interp_data (self);
 }
 
@@ -269,4 +324,14 @@ void
 _initialize_cli_interp (void)
 {
   interp_factory_register (INTERP_CONSOLE, cli_interp_factory);
+
+  /* If changing this, remember to update tui-interp.c as well.  */
+  observer_attach_normal_stop (cli_on_normal_stop);
+  observer_attach_end_stepping_range (cli_on_end_stepping_range);
+  observer_attach_signal_received (cli_on_signal_received);
+  observer_attach_signal_exited (cli_on_signal_exited);
+  observer_attach_exited (cli_on_exited);
+  observer_attach_no_history (cli_on_no_history);
+  observer_attach_sync_execution_done (cli_on_sync_execution_done);
+  observer_attach_command_error (cli_on_command_error);
 }
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 664543c..c6e3b7e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -437,8 +437,55 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-static struct ui current_ui_;
-struct ui *current_ui = &current_ui_;
+/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
+   It always exists and is created automatically when GDB starts
+   up.  */
+static struct ui main_ui_;
+
+struct ui *current_ui = &main_ui_;
+struct ui *ui_list = &main_ui_;
+
+/* Cleanup that restores the current UI.  */
+
+static void
+restore_ui_cleanup (void *data)
+{
+  current_ui = (struct ui *) data;
+}
+
+/* See top.h.  */
+
+void
+switch_thru_all_uis_init (struct switch_thru_all_uis *state)
+{
+  state->iter = ui_list;
+  state->old_chain = make_cleanup (restore_ui_cleanup, current_ui);
+}
+
+/* See top.h.  */
+
+int
+switch_thru_all_uis_cond (struct switch_thru_all_uis *state)
+{
+  if (state->iter != NULL)
+    {
+      current_ui = state->iter;
+      return 1;
+    }
+  else
+    {
+      do_cleanups (state->old_chain);
+      return 0;
+    }
+}
+
+/* See top.h.  */
+
+void
+switch_thru_all_uis_next (struct switch_thru_all_uis *state)
+{
+  state->iter = state->iter->next;
+}
 
 /* Get a pointer to the current UI's line buffer.  This is used to
    construct a whole line of input from partial input.  */
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 8ba6110..f9820cb 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -88,6 +88,17 @@ static void mi_on_sync_execution_done (void);
 
 static int report_initial_inferior (struct inferior *inf, void *closure);
 
+/* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and
+   returns NULL otherwise.  */
+
+static struct mi_interp *
+as_mi_interp (struct interp *interp)
+{
+  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
+    return (struct mi_interp *) interp_data (interp);
+  return NULL;
+}
+
 static void *
 mi_interpreter_init (struct interp *interp, int top_level)
 {
@@ -127,39 +138,8 @@ mi_interpreter_init (struct interp *interp, int top_level)
   mi->mi_uiout = mi_out_new (mi_version);
   mi->cli_uiout = cli_out_new (mi->out);
 
-  /* There are installed even if MI is not the top level interpreter.
-     The callbacks themselves decide whether to be skipped.  */
-  observer_attach_signal_received (mi_on_signal_received);
-  observer_attach_end_stepping_range (mi_on_end_stepping_range);
-  observer_attach_signal_exited (mi_on_signal_exited);
-  observer_attach_exited (mi_on_exited);
-  observer_attach_no_history (mi_on_no_history);
-
   if (top_level)
     {
-      observer_attach_new_thread (mi_new_thread);
-      observer_attach_thread_exit (mi_thread_exit);
-      observer_attach_inferior_added (mi_inferior_added);
-      observer_attach_inferior_appeared (mi_inferior_appeared);
-      observer_attach_inferior_exit (mi_inferior_exit);
-      observer_attach_inferior_removed (mi_inferior_removed);
-      observer_attach_record_changed (mi_record_changed);
-      observer_attach_normal_stop (mi_on_normal_stop);
-      observer_attach_target_resumed (mi_on_resume);
-      observer_attach_solib_loaded (mi_solib_loaded);
-      observer_attach_solib_unloaded (mi_solib_unloaded);
-      observer_attach_about_to_proceed (mi_about_to_proceed);
-      observer_attach_traceframe_changed (mi_traceframe_changed);
-      observer_attach_tsv_created (mi_tsv_created);
-      observer_attach_tsv_deleted (mi_tsv_deleted);
-      observer_attach_tsv_modified (mi_tsv_modified);
-      observer_attach_breakpoint_created (mi_breakpoint_created);
-      observer_attach_breakpoint_deleted (mi_breakpoint_deleted);
-      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
 	 case future version of GDB creates more than one inferior
@@ -311,6 +291,12 @@ mi_execute_command_wrapper (const char *cmd)
 static void
 mi_on_sync_execution_done (void)
 {
+  struct ui *ui = current_ui;
+  struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+
+  if (mi == NULL)
+    return;
+
   /* If MI is sync, then output the MI prompt now, indicating we're
      ready for further input.  */
   if (!mi_async_p ())
@@ -356,45 +342,56 @@ mi_command_loop (void *data)
 static void
 mi_new_thread (struct thread_info *t)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
   struct inferior *inf = find_inferior_ptid (t->ptid);
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   gdb_assert (inf);
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel, 
-		      "thread-created,id=\"%d\",group-id=\"i%d\"",
-		      t->global_num, inf->num);
-  gdb_flush (mi->event_channel);
+      if (mi == NULL)
+	continue;
 
-  do_cleanups (old_chain);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-created,id=\"%d\",group-id=\"i%d\"",
+			  t->global_num, inf->num);
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 static void
 mi_thread_exit (struct thread_info *t, int silent)
 {
-  struct mi_interp *mi;
-  struct inferior *inf;
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (silent)
     return;
 
-  inf = find_inferior_ptid (t->ptid);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  mi = (struct mi_interp *) top_level_interpreter_data ();
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+      if (mi == NULL)
+	continue;
 
-  fprintf_unfiltered (mi->event_channel, 
-		      "thread-exited,id=\"%d\",group-id=\"i%d\"",
-		      t->global_num, inf->num);
-  gdb_flush (mi->event_channel);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-exited,id=\"%d\",group-id=\"i%d\"",
+			  t->global_num, t->inf->num);
+      gdb_flush (mi->event_channel);
 
-  do_cleanups (old_chain);
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification on changing the state of record.  */
@@ -402,122 +399,155 @@ mi_thread_exit (struct thread_info *t, int silent)
 static void
 mi_record_changed (struct inferior *inferior, int started)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,  "record-%s,thread-group=\"i%d\"",
-		      started ? "started" : "stopped", inferior->num);
+      if (mi == NULL)
+	continue;
 
-  gdb_flush (mi->event_channel);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  do_cleanups (old_chain);
+      fprintf_unfiltered (mi->event_channel,  "record-%s,thread-group=\"i%d\"",
+			  started ? "started" : "stopped", inferior->num);
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 static void
 mi_inferior_added (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *interp;
+      struct mi_interp *mi;
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,
-		      "thread-group-added,id=\"i%d\"",
-		      inf->num);
-  gdb_flush (mi->event_channel);
+      /* We'll be called once for the initial inferior, before the top
+	 level interpreter is set.  */
+      interp = top_level_interpreter ();
+      if (interp == NULL)
+	continue;
 
-  do_cleanups (old_chain);
+      mi = as_mi_interp (interp);
+      if (mi == NULL)
+	continue;
+
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-group-added,id=\"i%d\"",
+			  inf->num);
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 static void
 mi_inferior_appeared (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,
-		      "thread-group-started,id=\"i%d\",pid=\"%d\"",
-		      inf->num, inf->pid);
-  gdb_flush (mi->event_channel);
+      if (mi == NULL)
+	continue;
 
-  do_cleanups (old_chain);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-group-started,id=\"i%d\",pid=\"%d\"",
+			  inf->num, inf->pid);
+      gdb_flush (mi->event_channel);
+      do_cleanups (old_chain);
+    }
 }
 
 static void
 mi_inferior_exit (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  if (inf->has_exit_code)
-    fprintf_unfiltered (mi->event_channel,
-			"thread-group-exited,id=\"i%d\",exit-code=\"%s\"",
-			inf->num, int_string (inf->exit_code, 8, 0, 0, 1));
-  else
-    fprintf_unfiltered (mi->event_channel,
-			"thread-group-exited,id=\"i%d\"", inf->num);
-  gdb_flush (mi->event_channel);
+      if (mi == NULL)
+	continue;
 
-  do_cleanups (old_chain);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      if (inf->has_exit_code)
+	fprintf_unfiltered (mi->event_channel,
+			    "thread-group-exited,id=\"i%d\",exit-code=\"%s\"",
+			    inf->num, int_string (inf->exit_code, 8, 0, 0, 1));
+      else
+	fprintf_unfiltered (mi->event_channel,
+			    "thread-group-exited,id=\"i%d\"", inf->num);
+
+      gdb_flush (mi->event_channel);
+      do_cleanups (old_chain);
+    }
 }
 
 static void
 mi_inferior_removed (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,
-		      "thread-group-removed,id=\"i%d\"",
-		      inf->num);
-  gdb_flush (mi->event_channel);
+      if (mi == NULL)
+	continue;
 
-  do_cleanups (old_chain);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-group-removed,id=\"i%d\"",
+			  inf->num);
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Return the MI interpreter, if it is active -- either because it's
    the top-level interpreter or the interpreter executing the current
    command.  Returns NULL if the MI interpreter is not being used.  */
 
-static struct interp *
-find_mi_interpreter (void)
+static struct mi_interp *
+find_mi_interp (void)
 {
-  struct interp *interp;
-
-  interp = top_level_interpreter ();
-  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
-    return interp;
-
-  interp = command_interp ();
-  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
-    return interp;
-
-  return NULL;
-}
+  struct mi_interp *mi;
 
-/* Return the MI_INTERP structure of the active MI interpreter.
-   Returns NULL if MI is not active.  */
+  mi = as_mi_interp (top_level_interpreter ());
+  if (mi != NULL)
+    return mi;
 
-static struct mi_interp *
-mi_interp_data (void)
-{
-  struct interp *interp = find_mi_interpreter ();
+  mi = as_mi_interp (command_interp ());
+  if (mi != NULL)
+    return mi;
 
-  if (interp != NULL)
-    return (struct mi_interp *) interp_data (interp);
   return NULL;
 }
 
@@ -530,13 +560,18 @@ mi_interp_data (void)
 static void
 mi_on_signal_received (enum gdb_signal siggnal)
 {
-  struct mi_interp *mi = mi_interp_data ();
+  struct switch_thru_all_uis state;
 
-  if (mi == NULL)
-    return;
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = find_mi_interp ();
+
+      if (mi == NULL)
+	continue;
 
-  print_signal_received_reason (mi->mi_uiout, siggnal);
-  print_signal_received_reason (mi->cli_uiout, siggnal);
+      print_signal_received_reason (mi->mi_uiout, siggnal);
+      print_signal_received_reason (mi->cli_uiout, siggnal);
+    }
 }
 
 /* Observer for the end_stepping_range notification.  */
@@ -544,13 +579,18 @@ mi_on_signal_received (enum gdb_signal siggnal)
 static void
 mi_on_end_stepping_range (void)
 {
-  struct mi_interp *mi = mi_interp_data ();
+  struct switch_thru_all_uis state;
 
-  if (mi == NULL)
-    return;
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = find_mi_interp ();
+
+      if (mi == NULL)
+	continue;
 
-  print_end_stepping_range_reason (mi->mi_uiout);
-  print_end_stepping_range_reason (mi->cli_uiout);
+      print_end_stepping_range_reason (mi->mi_uiout);
+      print_end_stepping_range_reason (mi->cli_uiout);
+    }
 }
 
 /* Observer for the signal_exited notification.  */
@@ -558,13 +598,18 @@ mi_on_end_stepping_range (void)
 static void
 mi_on_signal_exited (enum gdb_signal siggnal)
 {
-  struct mi_interp *mi = mi_interp_data ();
+  struct switch_thru_all_uis state;
 
-  if (mi == NULL)
-    return;
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = find_mi_interp ();
+
+      if (mi == NULL)
+	continue;
 
-  print_signal_exited_reason (mi->mi_uiout, siggnal);
-  print_signal_exited_reason (mi->cli_uiout, siggnal);
+      print_signal_exited_reason (mi->mi_uiout, siggnal);
+      print_signal_exited_reason (mi->cli_uiout, siggnal);
+    }
 }
 
 /* Observer for the exited notification.  */
@@ -572,13 +617,18 @@ mi_on_signal_exited (enum gdb_signal siggnal)
 static void
 mi_on_exited (int exitstatus)
 {
-  struct mi_interp *mi = mi_interp_data ();
+  struct switch_thru_all_uis state;
 
-  if (mi == NULL)
-    return;
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = find_mi_interp ();
+
+      if (mi == NULL)
+	continue;
 
-  print_exited_reason (mi->mi_uiout, exitstatus);
-  print_exited_reason (mi->cli_uiout, exitstatus);
+      print_exited_reason (mi->mi_uiout, exitstatus);
+      print_exited_reason (mi->cli_uiout, exitstatus);
+    }
 }
 
 /* Observer for the no_history notification.  */
@@ -586,17 +636,22 @@ mi_on_exited (int exitstatus)
 static void
 mi_on_no_history (void)
 {
-  struct mi_interp *mi = mi_interp_data ();
+  struct switch_thru_all_uis state;
 
-  if (mi == NULL)
-    return;
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = find_mi_interp ();
+
+      if (mi == NULL)
+	continue;
 
-  print_no_history_reason (mi->mi_uiout);
-  print_no_history_reason (mi->cli_uiout);
+      print_no_history_reason (mi->mi_uiout);
+      print_no_history_reason (mi->cli_uiout);
+    }
 }
 
 static void
-mi_on_normal_stop (struct bpstats *bs, int print_frame)
+mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
 {
   /* Since this can be called when CLI command is executing,
      using cli interpreter, be sure to use MI uiout for output,
@@ -677,6 +732,20 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame)
 }
 
 static void
+mi_on_normal_stop (struct bpstats *bs, int print_frame)
+{
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      if (as_mi_interp (top_level_interpreter ()) == NULL)
+	continue;
+
+      mi_on_normal_stop_1 (bs, print_frame);
+    }
+}
+
+static void
 mi_about_to_proceed (void)
 {
   /* Suppress output while calling an inferior function.  */
@@ -707,25 +776,33 @@ struct mi_suppress_notification mi_suppress_notification =
 static void
 mi_traceframe_changed (int tfnum, int tpnum)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (mi_suppress_notification.traceframe)
     return;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  if (tfnum >= 0)
-    fprintf_unfiltered (mi->event_channel, "traceframe-changed,"
-			"num=\"%d\",tracepoint=\"%d\"\n",
-			tfnum, tpnum);
-  else
-    fprintf_unfiltered (mi->event_channel, "traceframe-changed,end");
+      if (mi == NULL)
+	continue;
 
-  gdb_flush (mi->event_channel);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  do_cleanups (old_chain);
+      if (tfnum >= 0)
+	fprintf_unfiltered (mi->event_channel, "traceframe-changed,"
+			    "num=\"%d\",tracepoint=\"%d\"\n",
+			    tfnum, tpnum);
+      else
+	fprintf_unfiltered (mi->event_channel, "traceframe-changed,end");
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification on creating a trace state variable.  */
@@ -733,19 +810,27 @@ mi_traceframe_changed (int tfnum, int tpnum)
 static void
 mi_tsv_created (const struct trace_state_variable *tsv)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel, "tsv-created,"
-		      "name=\"%s\",initial=\"%s\"\n",
-		      tsv->name, plongest (tsv->initial_value));
+      if (mi == NULL)
+	continue;
 
-  gdb_flush (mi->event_channel);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  do_cleanups (old_chain);
+      fprintf_unfiltered (mi->event_channel, "tsv-created,"
+			  "name=\"%s\",initial=\"%s\"\n",
+			  tsv->name, plongest (tsv->initial_value));
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification on deleting a trace state variable.  */
@@ -753,21 +838,29 @@ mi_tsv_created (const struct trace_state_variable *tsv)
 static void
 mi_tsv_deleted (const struct trace_state_variable *tsv)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  if (tsv != NULL)
-    fprintf_unfiltered (mi->event_channel, "tsv-deleted,"
-			"name=\"%s\"\n", tsv->name);
-  else
-    fprintf_unfiltered (mi->event_channel, "tsv-deleted\n");
+      if (mi == NULL)
+	continue;
 
-  gdb_flush (mi->event_channel);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  do_cleanups (old_chain);
+      if (tsv != NULL)
+	fprintf_unfiltered (mi->event_channel, "tsv-deleted,"
+			    "name=\"%s\"\n", tsv->name);
+      else
+	fprintf_unfiltered (mi->event_channel, "tsv-deleted\n");
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification on modifying a trace state variable.  */
@@ -775,29 +868,39 @@ mi_tsv_deleted (const struct trace_state_variable *tsv)
 static void
 mi_tsv_modified (const struct trace_state_variable *tsv)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,
-		      "tsv-modified");
+      if (mi == NULL)
+	continue;
 
-  ui_out_redirect (mi_uiout, mi->event_channel);
+      mi_uiout = interp_ui_out (top_level_interpreter ());
 
-  ui_out_field_string (mi_uiout, "name", tsv->name);
-  ui_out_field_string (mi_uiout, "initial",
-		       plongest (tsv->initial_value));
-  if (tsv->value_known)
-    ui_out_field_string (mi_uiout, "current", plongest (tsv->value));
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  ui_out_redirect (mi_uiout, NULL);
+      fprintf_unfiltered (mi->event_channel,
+			  "tsv-modified");
 
-  gdb_flush (mi->event_channel);
+      ui_out_redirect (mi_uiout, mi->event_channel);
 
-  do_cleanups (old_chain);
+      ui_out_field_string (mi_uiout, "name", tsv->name);
+      ui_out_field_string (mi_uiout, "initial",
+			   plongest (tsv->initial_value));
+      if (tsv->value_known)
+	ui_out_field_string (mi_uiout, "current", plongest (tsv->value));
+
+      ui_out_redirect (mi_uiout, NULL);
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification about a created breakpoint.  */
@@ -805,9 +908,7 @@ mi_tsv_modified (const struct trace_state_variable *tsv)
 static void
 mi_breakpoint_created (struct breakpoint *b)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (mi_suppress_notification.breakpoint)
     return;
@@ -815,33 +916,45 @@ mi_breakpoint_created (struct breakpoint *b)
   if (b->number <= 0)
     return;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
-
-  fprintf_unfiltered (mi->event_channel,
-		      "breakpoint-created");
-  /* We want the output from gdb_breakpoint_query to go to
-     mi->event_channel.  One approach would be to just call
-     gdb_breakpoint_query, and then use mi_out_put to send the current
-     content of mi_outout into mi->event_channel.  However, that will
-     break if anything is output to mi_uiout prior to calling the
-     breakpoint_created notifications.  So, we use
-     ui_out_redirect.  */
-  ui_out_redirect (mi_uiout, mi->event_channel);
-  TRY
+  SWITCH_THRU_ALL_UIS (state)
     {
-      gdb_breakpoint_query (mi_uiout, b->number, NULL);
-    }
-  CATCH (e, RETURN_MASK_ERROR)
-    {
-    }
-  END_CATCH
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
+      struct cleanup *old_chain;
+
+      if (mi == NULL)
+	continue;
+
+      mi_uiout = interp_ui_out (top_level_interpreter ());
+
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      fprintf_unfiltered (mi->event_channel,
+			  "breakpoint-created");
+      /* We want the output from gdb_breakpoint_query to go to
+	 mi->event_channel.  One approach would be to just call
+	 gdb_breakpoint_query, and then use mi_out_put to send the current
+	 content of mi_outout into mi->event_channel.  However, that will
+	 break if anything is output to mi_uiout prior to calling the
+	 breakpoint_created notifications.  So, we use
+	 ui_out_redirect.  */
+      ui_out_redirect (mi_uiout, mi->event_channel);
+      TRY
+	{
+	  gdb_breakpoint_query (mi_uiout, b->number, NULL);
+	}
+      CATCH (e, RETURN_MASK_ERROR)
+	{
+	}
+      END_CATCH
 
-  ui_out_redirect (mi_uiout, NULL);
+      ui_out_redirect (mi_uiout, NULL);
 
-  gdb_flush (mi->event_channel);
+      gdb_flush (mi->event_channel);
 
-  do_cleanups (old_chain);
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification about deleted breakpoint.  */
@@ -849,8 +962,7 @@ mi_breakpoint_created (struct breakpoint *b)
 static void
 mi_breakpoint_deleted (struct breakpoint *b)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (mi_suppress_notification.breakpoint)
     return;
@@ -858,15 +970,24 @@ mi_breakpoint_deleted (struct breakpoint *b)
   if (b->number <= 0)
     return;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"",
-		      b->number);
+      if (mi == NULL)
+	continue;
 
-  gdb_flush (mi->event_channel);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  do_cleanups (old_chain);
+      fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"",
+			  b->number);
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification about modified breakpoint.  */
@@ -874,9 +995,7 @@ mi_breakpoint_deleted (struct breakpoint *b)
 static void
 mi_breakpoint_modified (struct breakpoint *b)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (mi_suppress_notification.breakpoint)
     return;
@@ -884,44 +1003,61 @@ mi_breakpoint_modified (struct breakpoint *b)
   if (b->number <= 0)
     return;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
-
-  fprintf_unfiltered (mi->event_channel,
-		      "breakpoint-modified");
-  /* We want the output from gdb_breakpoint_query to go to
-     mi->event_channel.  One approach would be to just call
-     gdb_breakpoint_query, and then use mi_out_put to send the current
-     content of mi_outout into mi->event_channel.  However, that will
-     break if anything is output to mi_uiout prior to calling the
-     breakpoint_created notifications.  So, we use
-     ui_out_redirect.  */
-  ui_out_redirect (mi_uiout, mi->event_channel);
-  TRY
+  SWITCH_THRU_ALL_UIS (state)
     {
-      gdb_breakpoint_query (mi_uiout, b->number, NULL);
-    }
-  CATCH (e, RETURN_MASK_ERROR)
-    {
-    }
-  END_CATCH
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
+
+      if (mi == NULL)
+	continue;
+
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+      fprintf_unfiltered (mi->event_channel,
+			  "breakpoint-modified");
+      /* We want the output from gdb_breakpoint_query to go to
+	 mi->event_channel.  One approach would be to just call
+	 gdb_breakpoint_query, and then use mi_out_put to send the current
+	 content of mi_outout into mi->event_channel.  However, that will
+	 break if anything is output to mi_uiout prior to calling the
+	 breakpoint_created notifications.  So, we use
+	 ui_out_redirect.  */
+      ui_out_redirect (mi->mi_uiout, mi->event_channel);
+      TRY
+	{
+	  gdb_breakpoint_query (mi->mi_uiout, b->number, NULL);
+	}
+      CATCH (e, RETURN_MASK_ERROR)
+	{
+	}
+      END_CATCH
 
-  ui_out_redirect (mi_uiout, NULL);
+      ui_out_redirect (mi->mi_uiout, NULL);
 
-  gdb_flush (mi->event_channel);
+      gdb_flush (mi->event_channel);
 
-  do_cleanups (old_chain);
+      do_cleanups (old_chain);
+    }
 }
 
 static int
 mi_output_running_pid (struct thread_info *info, void *arg)
 {
   ptid_t *ptid = (ptid_t *) arg;
+  struct switch_thru_all_uis state;
 
-  if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
-    fprintf_unfiltered (raw_stdout,
-			"*running,thread-id=\"%d\"\n",
-			info->global_num);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+
+      if (mi == NULL)
+	continue;
+
+      if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
+	fprintf_unfiltered (raw_stdout,
+			    "*running,thread-id=\"%d\"\n",
+			    info->global_num);
+    }
 
   return 0;
 }
@@ -939,19 +1075,8 @@ mi_inferior_count (struct inferior *inf, void *arg)
 }
 
 static void
-mi_on_resume (ptid_t ptid)
+mi_on_resume_1 (ptid_t ptid)
 {
-  struct thread_info *tp = NULL;
-
-  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
-    tp = inferior_thread ();
-  else
-    tp = find_thread_ptid (ptid);
-
-  /* Suppress output while calling an inferior function.  */
-  if (tp->control.in_infcall)
-    return;
-
   /* To cater for older frontends, emit ^running, but do it only once
      per each command.  We do it here, since at this point we know
      that the target was successfully resumed, and in non-async mode,
@@ -1006,64 +1131,116 @@ mi_on_resume (ptid_t ptid)
 }
 
 static void
-mi_solib_loaded (struct so_list *solib)
+mi_on_resume (ptid_t ptid)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *uiout = interp_ui_out (top_level_interpreter ());
-  struct cleanup *old_chain;
-
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  struct thread_info *tp = NULL;
+  struct switch_thru_all_uis state;
 
-  fprintf_unfiltered (mi->event_channel, "library-loaded");
+  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
+    tp = inferior_thread ();
+  else
+    tp = find_thread_ptid (ptid);
 
-  ui_out_redirect (uiout, mi->event_channel);
+  /* Suppress output while calling an inferior function.  */
+  if (tp->control.in_infcall)
+    return;
 
-  ui_out_field_string (uiout, "id", solib->so_original_name);
-  ui_out_field_string (uiout, "target-name", solib->so_original_name);
-  ui_out_field_string (uiout, "host-name", solib->so_name);
-  ui_out_field_int (uiout, "symbols-loaded", solib->symbols_loaded);
-  if (!gdbarch_has_global_solist (target_gdbarch ()))
+  SWITCH_THRU_ALL_UIS (state)
     {
-      ui_out_field_fmt (uiout, "thread-group", "i%d",
-			current_inferior ()->num);
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct cleanup *old_chain;
+
+      if (mi == NULL)
+	continue;
+
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      mi_on_resume_1 (ptid);
+
+      do_cleanups (old_chain);
     }
+}
 
-  ui_out_redirect (uiout, NULL);
+static void
+mi_solib_loaded (struct so_list *solib)
+{
+  struct switch_thru_all_uis state;
 
-  gdb_flush (mi->event_channel);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *uiout;
+      struct cleanup *old_chain;
 
-  do_cleanups (old_chain);
+      if (mi == NULL)
+	continue;
+
+      uiout = interp_ui_out (top_level_interpreter ());
+
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
+
+      fprintf_unfiltered (mi->event_channel, "library-loaded");
+
+      ui_out_redirect (uiout, mi->event_channel);
+
+      ui_out_field_string (uiout, "id", solib->so_original_name);
+      ui_out_field_string (uiout, "target-name", solib->so_original_name);
+      ui_out_field_string (uiout, "host-name", solib->so_name);
+      ui_out_field_int (uiout, "symbols-loaded", solib->symbols_loaded);
+      if (!gdbarch_has_global_solist (target_gdbarch ()))
+	{
+	  ui_out_field_fmt (uiout, "thread-group", "i%d",
+			    current_inferior ()->num);
+	}
+
+      ui_out_redirect (uiout, NULL);
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 static void
 mi_solib_unloaded (struct so_list *solib)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *uiout = interp_ui_out (top_level_interpreter ());
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *uiout;
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel, "library-unloaded");
+      if (mi == NULL)
+	continue;
 
-  ui_out_redirect (uiout, mi->event_channel);
+      uiout = interp_ui_out (top_level_interpreter ());
 
-  ui_out_field_string (uiout, "id", solib->so_original_name);
-  ui_out_field_string (uiout, "target-name", solib->so_original_name);
-  ui_out_field_string (uiout, "host-name", solib->so_name);
-  if (!gdbarch_has_global_solist (target_gdbarch ()))
-    {
-      ui_out_field_fmt (uiout, "thread-group", "i%d",
-			current_inferior ()->num);
-    }
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  ui_out_redirect (uiout, NULL);
+      fprintf_unfiltered (mi->event_channel, "library-unloaded");
 
-  gdb_flush (mi->event_channel);
+      ui_out_redirect (uiout, mi->event_channel);
 
-  do_cleanups (old_chain);
+      ui_out_field_string (uiout, "id", solib->so_original_name);
+      ui_out_field_string (uiout, "target-name", solib->so_original_name);
+      ui_out_field_string (uiout, "host-name", solib->so_name);
+      if (!gdbarch_has_global_solist (target_gdbarch ()))
+	{
+	  ui_out_field_fmt (uiout, "thread-group", "i%d",
+			    current_inferior ()->num);
+	}
+
+      ui_out_redirect (uiout, NULL);
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification about the command parameter change.  */
@@ -1071,29 +1248,38 @@ mi_solib_unloaded (struct so_list *solib)
 static void
 mi_command_param_changed (const char *param, const char *value)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (mi_suppress_notification.cmd_param_changed)
     return;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,
-		      "cmd-param-changed");
+      if (mi == NULL)
+	continue;
 
-  ui_out_redirect (mi_uiout, mi->event_channel);
+      mi_uiout = interp_ui_out (top_level_interpreter ());
 
-  ui_out_field_string (mi_uiout, "param", param);
-  ui_out_field_string (mi_uiout, "value", value);
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  ui_out_redirect (mi_uiout, NULL);
+      fprintf_unfiltered (mi->event_channel, "cmd-param-changed");
 
-  gdb_flush (mi->event_channel);
+      ui_out_redirect (mi_uiout, mi->event_channel);
 
-  do_cleanups (old_chain);
+      ui_out_field_string (mi_uiout, "param", param);
+      ui_out_field_string (mi_uiout, "value", value);
+
+      ui_out_redirect (mi_uiout, NULL);
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 /* Emit notification about the target memory change.  */
@@ -1102,49 +1288,58 @@ static void
 mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr,
 		   ssize_t len, const bfd_byte *myaddr)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
-  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
-  struct obj_section *sec;
-  struct cleanup *old_chain;
+  struct switch_thru_all_uis state;
 
   if (mi_suppress_notification.memory)
     return;
 
-  old_chain = make_cleanup_restore_target_terminal ();
-  target_terminal_ours_for_output ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
+      struct obj_section *sec;
+      struct cleanup *old_chain;
 
-  fprintf_unfiltered (mi->event_channel,
-		      "memory-changed");
+      if (mi == NULL)
+	continue;
 
-  ui_out_redirect (mi_uiout, mi->event_channel);
+      mi_uiout = interp_ui_out (top_level_interpreter ());
 
-  ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num);
-  ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr);
-  ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len));
+      old_chain = make_cleanup_restore_target_terminal ();
+      target_terminal_ours_for_output ();
 
-  /* Append 'type=code' into notification if MEMADDR falls in the range of
-     sections contain code.  */
-  sec = find_pc_section (memaddr);
-  if (sec != NULL && sec->objfile != NULL)
-    {
-      flagword flags = bfd_get_section_flags (sec->objfile->obfd,
-					      sec->the_bfd_section);
+      fprintf_unfiltered (mi->event_channel, "memory-changed");
 
-      if (flags & SEC_CODE)
-	ui_out_field_string (mi_uiout, "type", "code");
-    }
+      ui_out_redirect (mi_uiout, mi->event_channel);
 
-  ui_out_redirect (mi_uiout, NULL);
+      ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num);
+      ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr);
+      ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len));
 
-  gdb_flush (mi->event_channel);
+      /* Append 'type=code' into notification if MEMADDR falls in the range of
+	 sections contain code.  */
+      sec = find_pc_section (memaddr);
+      if (sec != NULL && sec->objfile != NULL)
+	{
+	  flagword flags = bfd_get_section_flags (sec->objfile->obfd,
+						  sec->the_bfd_section);
 
-  do_cleanups (old_chain);
+	  if (flags & SEC_CODE)
+	    ui_out_field_string (mi_uiout, "type", "code");
+	}
+
+      ui_out_redirect (mi_uiout, NULL);
+
+      gdb_flush (mi->event_channel);
+
+      do_cleanups (old_chain);
+    }
 }
 
 static int
 report_initial_inferior (struct inferior *inf, void *closure)
 {
-  /* This function is called from mi_intepreter_init, and since
+  /* This function is called from mi_interpreter_init, and since
      mi_inferior_added assumes that inferior is fully initialized
      and top_level_interpreter_data is set, we cannot call
      it here.  */
@@ -1250,4 +1445,32 @@ _initialize_mi_interp (void)
   interp_factory_register (INTERP_MI2, mi_interp_factory);
   interp_factory_register (INTERP_MI3, mi_interp_factory);
   interp_factory_register (INTERP_MI, mi_interp_factory);
+
+  observer_attach_signal_received (mi_on_signal_received);
+  observer_attach_end_stepping_range (mi_on_end_stepping_range);
+  observer_attach_signal_exited (mi_on_signal_exited);
+  observer_attach_exited (mi_on_exited);
+  observer_attach_no_history (mi_on_no_history);
+  observer_attach_new_thread (mi_new_thread);
+  observer_attach_thread_exit (mi_thread_exit);
+  observer_attach_inferior_added (mi_inferior_added);
+  observer_attach_inferior_appeared (mi_inferior_appeared);
+  observer_attach_inferior_exit (mi_inferior_exit);
+  observer_attach_inferior_removed (mi_inferior_removed);
+  observer_attach_record_changed (mi_record_changed);
+  observer_attach_normal_stop (mi_on_normal_stop);
+  observer_attach_target_resumed (mi_on_resume);
+  observer_attach_solib_loaded (mi_solib_loaded);
+  observer_attach_solib_unloaded (mi_solib_unloaded);
+  observer_attach_about_to_proceed (mi_about_to_proceed);
+  observer_attach_traceframe_changed (mi_traceframe_changed);
+  observer_attach_tsv_created (mi_tsv_created);
+  observer_attach_tsv_deleted (mi_tsv_deleted);
+  observer_attach_tsv_modified (mi_tsv_modified);
+  observer_attach_breakpoint_created (mi_breakpoint_created);
+  observer_attach_breakpoint_deleted (mi_breakpoint_deleted);
+  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);
 }
diff --git a/gdb/top.h b/gdb/top.h
index f18b79e..805022f 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -36,6 +36,9 @@ struct tl_interp_info;
 
 struct ui
 {
+  /* Pointer to next in singly-linked list.  */
+  struct ui *next;
+
   /* The UI's command line buffer.  This is to used to accumulate
      input until we have a whole command line.  */
   struct buffer line_buffer;
@@ -83,8 +86,34 @@ struct ui
   struct ui_file *m_gdb_stdlog;
 };
 
+/* The current UI.  */
 extern struct ui *current_ui;
 
+/* The list of all UIs.  */
+extern struct ui *ui_list;
+
+/* State for SWITCH_THRU_ALL_UIS.  Declared here because it is meant
+   to be created on the stack, but should be treated as opaque.  */
+struct switch_thru_all_uis
+{
+  struct ui *iter;
+  struct cleanup *old_chain;
+};
+
+/* Functions to drive SWITCH_THRU_ALL_UIS.  Though declared here by
+   necessity, these functions should not be used other than via the
+   SWITCH_THRU_ALL_UIS macro defined below.  */
+extern void switch_thru_all_uis_init (struct switch_thru_all_uis *state);
+extern int switch_thru_all_uis_cond (struct switch_thru_all_uis *state);
+extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
+
+  /* Traverse through all UI, and switch the current UI to the one
+     being iterated.  */
+#define SWITCH_THRU_ALL_UIS(STATE)		\
+  for (switch_thru_all_uis_init (&STATE);		\
+       switch_thru_all_uis_cond (&STATE);		\
+       switch_thru_all_uis_next (&STATE))		\
+
 /* From top.c.  */
 extern char *saved_command_line;
 extern FILE *instream;
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 8afe46c..7691f8c 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -38,8 +38,16 @@ static struct ui_out *tui_ui_out (struct interp *self);
    gdb.  */
 static int tui_start_enabled = 0;
 
-/* The TUI interpreter.  */
-static struct interp *tui_interp;
+/* Returns the INTERP if the INTERP is a TUI, and returns NULL
+   otherwise.  */
+
+static struct interp *
+as_tui_interp (struct interp *interp)
+{
+  if (strcmp (interp_name (interp), INTERP_TUI) == 0)
+    return interp;
+  return NULL;
+}
 
 /* Cleanup the tui before exiting.  */
 
@@ -60,10 +68,17 @@ tui_exit (void)
 static void
 tui_on_normal_stop (struct bpstats *bs, int print_frame)
 {
-  if (!interp_quiet_p (tui_interp))
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
     {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
       if (print_frame)
-	print_stop_event (tui_ui_out (tui_interp));
+	print_stop_event (tui_ui_out (tui));
     }
 }
 
@@ -72,8 +87,17 @@ tui_on_normal_stop (struct bpstats *bs, int print_frame)
 static void
 tui_on_signal_received (enum gdb_signal siggnal)
 {
-  if (!interp_quiet_p (tui_interp))
-    print_signal_received_reason (tui_ui_out (tui_interp), siggnal);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
+      print_signal_received_reason (tui_ui_out (tui), siggnal);
+    }
 }
 
 /* Observer for the end_stepping_range notification.  */
@@ -81,8 +105,17 @@ tui_on_signal_received (enum gdb_signal siggnal)
 static void
 tui_on_end_stepping_range (void)
 {
-  if (!interp_quiet_p (tui_interp))
-    print_end_stepping_range_reason (tui_ui_out (tui_interp));
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
+      print_end_stepping_range_reason (tui_ui_out (tui));
+    }
 }
 
 /* Observer for the signal_exited notification.  */
@@ -90,8 +123,17 @@ tui_on_end_stepping_range (void)
 static void
 tui_on_signal_exited (enum gdb_signal siggnal)
 {
-  if (!interp_quiet_p (tui_interp))
-    print_signal_exited_reason (tui_ui_out (tui_interp), siggnal);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
+      print_signal_exited_reason (tui_ui_out (tui), siggnal);
+    }
 }
 
 /* Observer for the exited notification.  */
@@ -99,8 +141,17 @@ tui_on_signal_exited (enum gdb_signal siggnal)
 static void
 tui_on_exited (int exitstatus)
 {
-  if (!interp_quiet_p (tui_interp))
-    print_exited_reason (tui_ui_out (tui_interp), exitstatus);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
+      print_exited_reason (tui_ui_out (tui), exitstatus);
+    }
 }
 
 /* Observer for the no_history notification.  */
@@ -108,8 +159,17 @@ tui_on_exited (int exitstatus)
 static void
 tui_on_no_history (void)
 {
-  if (!interp_quiet_p (tui_interp))
-    print_no_history_reason (tui_ui_out (tui_interp));
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
+      print_no_history_reason (tui_ui_out (tui));
+    }
 }
 
 /* Observer for the sync_execution_done notification.  */
@@ -117,8 +177,12 @@ tui_on_no_history (void)
 static void
 tui_on_sync_execution_done (void)
 {
-  if (!interp_quiet_p (tui_interp))
-    display_gdb_prompt (NULL);
+  struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+  if (tui == NULL)
+    return;
+
+  display_gdb_prompt (NULL);
 }
 
 /* Observer for the command_error notification.  */
@@ -126,8 +190,12 @@ tui_on_sync_execution_done (void)
 static void
 tui_on_command_error (void)
 {
-  if (!interp_quiet_p (tui_interp))
-    display_gdb_prompt (NULL);
+  struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+  if (tui == NULL)
+    return;
+
+  display_gdb_prompt (NULL);
 }
 
 /* These implement the TUI interpreter.  */
@@ -138,9 +206,6 @@ tui_init (struct interp *self, int top_level)
   /* Install exit handler to leave the screen in a good shape.  */
   atexit (tui_exit);
 
-  if (top_level)
-    tui_interp = self;
-
   tui_initialize_static_data ();
 
   tui_initialize_io ();
@@ -148,16 +213,6 @@ tui_init (struct interp *self, int top_level)
   if (ui_file_isatty (gdb_stdout))
     tui_initialize_readline ();
 
-  /* If changing this, remember to update cli-interp.c as well.  */
-  observer_attach_normal_stop (tui_on_normal_stop);
-  observer_attach_signal_received (tui_on_signal_received);
-  observer_attach_end_stepping_range (tui_on_end_stepping_range);
-  observer_attach_signal_exited (tui_on_signal_exited);
-  observer_attach_exited (tui_on_exited);
-  observer_attach_no_history (tui_on_no_history);
-  observer_attach_sync_execution_done (tui_on_sync_execution_done);
-  observer_attach_command_error (tui_on_command_error);
-
   return NULL;
 }
 
@@ -246,4 +301,14 @@ _initialize_tui_interp (void)
       xfree (interpreter_p);
       interpreter_p = xstrdup (INTERP_TUI);
     }
+
+  /* If changing this, remember to update cli-interp.c as well.  */
+  observer_attach_normal_stop (tui_on_normal_stop);
+  observer_attach_signal_received (tui_on_signal_received);
+  observer_attach_end_stepping_range (tui_on_end_stepping_range);
+  observer_attach_signal_exited (tui_on_signal_exited);
+  observer_attach_exited (tui_on_exited);
+  observer_attach_no_history (tui_on_no_history);
+  observer_attach_sync_execution_done (tui_on_sync_execution_done);
+  observer_attach_command_error (tui_on_command_error);
 }
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 08/34] Always run async signal handlers in the main UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (23 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 17/34] Introduce display_mi_prompt Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-19 19:28   ` Simon Marchi
  2016-05-06 12:43 ` [PATCH v3 07/34] Make the intepreters output to all UIs Pedro Alves
                   ` (10 subsequent siblings)
  35 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

Async signal handlers have no connection to whichever was the current
UI, and thus always run on the main one.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-loop.c: Include top.h.
	(invoke_async_signal_handlers): Switch to the main UI.
	* event-top.c (main_ui_): Update comment.
	(main_ui): New global.
	* top.h (main_ui): Declare.
---
 gdb/event-loop.c | 4 ++++
 gdb/event-top.c  | 5 ++---
 gdb/top.h        | 5 +++++
 3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index 60ef2a5..fe28305 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -35,6 +35,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.  */
@@ -967,6 +968,9 @@ invoke_async_signal_handlers (void)
 	break;
       any_ready = 1;
       async_handler_ptr->ready = 0;
+      /* Async signal handlers have no connection to whichever was the
+	 current UI, and thus always run on the main one.  */
+      current_ui = main_ui;
       (*async_handler_ptr->proc) (async_handler_ptr->client_data);
     }
 
diff --git a/gdb/event-top.c b/gdb/event-top.c
index c6e3b7e..63f6896 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -437,11 +437,10 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
-   It always exists and is created automatically when GDB starts
-   up.  */
+/* The main UI.  */
 static struct ui main_ui_;
 
+struct ui *main_ui = &main_ui_;
 struct ui *current_ui = &main_ui_;
 struct ui *ui_list = &main_ui_;
 
diff --git a/gdb/top.h b/gdb/top.h
index 805022f..8f01f78 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -86,6 +86,11 @@ struct ui
   struct ui_file *m_gdb_stdlog;
 };
 
+/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
+   It always exists and is created automatically when GDB starts
+   up.  */
+extern struct ui *main_ui;
+
 /* The current UI.  */
 extern struct ui *current_ui;
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 10/34] Make input_fd be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (18 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 12/34] Delete def_uiout Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-06 12:43 ` [PATCH v3 25/34] Only send sync execution command output to the UI that ran the command Pedro Alves
                   ` (15 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

And with that, we can switch the current UI to the UI whose input
descriptor woke up the event loop.  IOW, if the user types in UI 2,
the event loop wakes up, switches to UI 2, and processes the input.
Next the user types in UI 3, the event loop wakes up and switches to
UI 3, etc.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-top.c (input_fd): Delete.
	(stdin_event_handler): Switch to the UI whose input descriptor got
	the event.  Adjust to per-UI input_fd.
	(gdb_setup_readline): Don't set the input_fd global.  Adjust to
	per-UI input_fd.
	(gdb_disable_readline): Adjust to per-UI input_fd.
	* event-top.h (input_fd): Delete declaration.
	* linux-nat.c (linux_nat_terminal_inferior): Don't remove input_fd
	from the event-loop here.
	(linux_nat_terminal_ours): Don't register input_fd in the
	event-loop here.
	* main.c (captured_main): Adjust to per-UI input_fd.
	* remote.c (remote_terminal_inferior): Don't remove input_fd from
	the event-loop here.
	(remote_terminal_ours): Don't register input_fd in the event-loop
	here.
	* target.c: Include top.h and event-top.h.
	(target_terminal_inferior): Remove input_fd from the event-loop
	here.
	(target_terminal_ours): Register input_fd in the event-loop.
	* top.h (struct ui) <input_fd>: New field.
---
 gdb/event-top.c | 33 ++++++++++++++-------------------
 gdb/event-top.h |  1 -
 gdb/linux-nat.c |  2 --
 gdb/main.c      |  1 +
 gdb/remote.c    |  2 --
 gdb/target.c    | 16 ++++++++++++++++
 gdb/top.h       |  4 ++++
 7 files changed, 35 insertions(+), 24 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 3e2f778..1d36b81 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -94,10 +94,6 @@ int async_command_editing_p;
    asynchronous execution command.  */
 int exec_done_display_p = 0;
 
-/* This is the file descriptor for the input stream that GDB uses to
-   read commands from.  */
-int input_fd;
-
 /* Used by the stdin event handler to compensate for missed stdin events.
    Setting this to a non-zero value inside an stdin callback makes the callback
    run again.  */
@@ -503,12 +499,16 @@ get_command_line_buffer (void)
 void
 stdin_event_handler (int error, gdb_client_data client_data)
 {
-  struct ui *ui = current_ui;
+  struct ui *ui = (struct ui *) client_data;
+
+  /* Switch to the UI whose input descriptor woke up the event
+     loop.  */
+  current_ui = ui;
 
   if (error)
     {
       printf_unfiltered (_("error detected on stdin\n"));
-      delete_file_handler (input_fd);
+      delete_file_handler (ui->input_fd);
       /* If stdin died, we may as well kill gdb.  */
       quit_command ((char *) 0, stdin == ui->instream);
     }
@@ -1270,18 +1270,11 @@ gdb_setup_readline (void)
   /* Tell readline to use the same input stream that gdb uses.  */
   rl_instream = ui->instream;
 
-  /* Get a file descriptor for the input stream, so that we can
-     register it with the event loop.  */
-  input_fd = fileno (ui->instream);
-
-  /* Now we need to create the event sources for the input file
-     descriptor.  */
-  /* At this point in time, this is the only event source that we
-     register with the even loop.  Another source is going to be the
-     target program (inferior), but that must be registered only when
-     it actually exists (I.e. after we say 'run' or after we connect
-     to a remote target.  */
-  add_file_handler (input_fd, stdin_event_handler, 0);
+  /* Now create the event source for this UI's input file descriptor.
+     Another source is going to be the target program (inferior), but
+     that must be registered only when it actually exists (I.e. after
+     we say 'run' or after we connect to a remote target.  */
+  add_file_handler (ui->input_fd, stdin_event_handler, ui);
 }
 
 /* Disable command input through the standard CLI channels.  Used in
@@ -1290,6 +1283,8 @@ gdb_setup_readline (void)
 void
 gdb_disable_readline (void)
 {
+  struct ui *ui = current_ui;
+
   /* FIXME - It is too heavyweight to delete and remake these every
      time you run an interpreter that needs readline.  It is probably
      better to have the interpreters cache these, which in turn means
@@ -1304,5 +1299,5 @@ gdb_disable_readline (void)
 #endif
 
   gdb_rl_callback_handler_remove ();
-  delete_file_handler (input_fd);
+  delete_file_handler (ui->input_fd);
 }
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 04956a5..4fe7737 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -57,7 +57,6 @@ extern void async_enable_stdin (void);
 extern int async_command_editing_p;
 extern int exec_done_display_p;
 extern struct prompts the_prompts;
-extern int input_fd;
 extern void (*after_char_processing_hook) (void);
 extern int call_stdin_event_handler_again_p;
 extern void gdb_readline_no_editing_callback (void *client_data);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index b75153c..451df6c 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4287,7 +4287,6 @@ linux_nat_terminal_inferior (struct target_ops *self)
   if (!async_terminal_is_ours)
     return;
 
-  delete_file_handler (input_fd);
   async_terminal_is_ours = 0;
   set_sigint_trap ();
 }
@@ -4313,7 +4312,6 @@ linux_nat_terminal_ours (struct target_ops *self)
     return;
 
   clear_sigint_trap ();
-  add_file_handler (input_fd, stdin_event_handler, 0);
   async_terminal_is_ours = 1;
 }
 
diff --git a/gdb/main.c b/gdb/main.c
index 7d7b52a..d862759 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -508,6 +508,7 @@ captured_main (void *data)
 
   saved_command_line = (char *) xstrdup ("");
   ui->instream = stdin;
+  ui->input_fd = fileno (stdin);
 
 #ifdef __MINGW32__
   /* Ensure stderr is unbuffered.  A Cygwin pty or pipe is implemented
diff --git a/gdb/remote.c b/gdb/remote.c
index 1f0d67c..501f3c6 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5924,7 +5924,6 @@ remote_terminal_inferior (struct target_ops *self)
      can go away.  */
   if (!remote_async_terminal_ours_p)
     return;
-  delete_file_handler (input_fd);
   remote_async_terminal_ours_p = 0;
   /* NOTE: At this point we could also register our selves as the
      recipient of all input.  Any characters typed could then be
@@ -5937,7 +5936,6 @@ remote_terminal_ours (struct target_ops *self)
   /* See FIXME in remote_terminal_inferior.  */
   if (remote_async_terminal_ours_p)
     return;
-  add_file_handler (input_fd, stdin_event_handler, 0);
   remote_async_terminal_ours_p = 1;
 }
 
diff --git a/gdb/target.c b/gdb/target.c
index a9744c4..2d16c96 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -43,6 +43,8 @@
 #include "agent.h"
 #include "auxv.h"
 #include "target-debug.h"
+#include "top.h"
+#include "event-top.h"
 
 static void target_info (char *, int);
 
@@ -477,6 +479,8 @@ target_terminal_is_ours (void)
 void
 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
@@ -484,6 +488,11 @@ target_terminal_inferior (void)
   if (target_can_async_p () && !sync_execution)
     return;
 
+  /* Always delete the current UI's input file handler, regardless of
+     terminal_state, because terminal_state is only valid for the main
+     UI.  */
+  delete_file_handler (ui->input_fd);
+
   if (terminal_state == terminal_is_inferior)
     return;
 
@@ -503,6 +512,13 @@ target_terminal_inferior (void)
 void
 target_terminal_ours (void)
 {
+  struct ui *ui = current_ui;
+
+  /* Always add the current UI's input file handler, regardless of
+     terminal_state, because terminal_state is only valid for the main
+     UI.  */
+  add_file_handler (ui->input_fd, stdin_event_handler, ui);
+
   if (terminal_state == terminal_is_ours)
     return;
 
diff --git a/gdb/top.h b/gdb/top.h
index bb84097..c50c0c9 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -74,6 +74,10 @@ struct ui
      interacting via a GUI.  */
   FILE *instream;
 
+  /* The file descriptor for the input stream, so that we can register
+     it with the event loop.  */
+  int input_fd;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 17/34] Introduce display_mi_prompt
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (22 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 05/34] Make the interpreters " Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-06 12:43 ` [PATCH v3 08/34] Always run async signal handlers in the main UI Pedro Alves
                   ` (11 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

Just a refactor.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* mi/mi-interp.c (display_mi_prompt): New function.
---
 gdb/mi/mi-interp.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 8f6a57b..b4d498d 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -88,6 +88,15 @@ static void mi_on_sync_execution_done (void);
 
 static int report_initial_inferior (struct inferior *inf, void *closure);
 
+/* Display the MI prompt.  */
+
+static void
+display_mi_prompt (void)
+{
+  fputs_unfiltered ("(gdb) \n", raw_stdout);
+  gdb_flush (raw_stdout);
+}
+
 /* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and
    returns NULL otherwise.  */
 
@@ -299,10 +308,7 @@ mi_on_sync_execution_done (void)
   /* If MI is sync, then output the MI prompt now, indicating we're
      ready for further input.  */
   if (!mi_async_p ())
-    {
-      fputs_unfiltered ("(gdb) \n", raw_stdout);
-      gdb_flush (raw_stdout);
-    }
+    display_mi_prompt ();
 }
 
 /* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER.  */
@@ -318,10 +324,7 @@ mi_execute_command_input_handler (char *cmd)
      'synchronous_command_done' observer when the target next
      stops.  */
   if (!sync_execution)
-    {
-      fputs_unfiltered ("(gdb) \n", raw_stdout);
-      gdb_flush (raw_stdout);
-    }
+    display_mi_prompt ();
 }
 
 static void
@@ -332,8 +335,7 @@ mi_command_loop (void *data)
   sevenbit_strings = 1;
 
   /* Tell the world that we're alive.  */
-  fputs_unfiltered ("(gdb) \n", raw_stdout);
-  gdb_flush (raw_stdout);
+  display_mi_prompt ();
 
   start_event_loop ();
 }
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 04/34] Make gdb_stdout&co be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (16 preceding siblings ...)
  2016-05-06 12:42 ` [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-06 12:43 ` [PATCH v3 12/34] Delete def_uiout Pedro Alves
                   ` (17 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

We need to have these send output to the proper UI.

However, this patch still make them look like globals.  Kind of like
__thread variables, if you will.  Changing everything throughout to
write something like current_ui->gdb_stdout instead would be massive
overkill, IMNSHO.

This leaves gdb_stdtargin/stdtarg/stdtargerr global, but maybe that was a
mistake, I'm not sure -- IIRC, MI formats target I/O differently, so
if we have a separate MI channel, then I guess target output should go
there instead of to gdb's stdout.  OTOH, maybe GDB should send that
instead to "set inferior-tty", instead of multiplexing it over MI.  We
can always fix those later when it gets clearer where they should go.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* main.c (gdb_stdout, gdb_stderr, gdb_stdlog, gdb_stdin): Delete
	globals.
	(gen_ret_current_ui_field_ptr): New macro.  Use it to generate
	wrappers for gdb_stdout, gdb_stderr, gdb_stdlog and gdb_stdin.
	* top.h (struct ui) <m_gdb_stdout, m_gdb_stdin, m_gdb_stderr,
	m_gdb_stdlog>: New fields.
	(current_ui_gdb_stdout_ptr, current_ui_gdb_stdin_ptr)
	(current_ui_gdb_stderr_ptr, current_ui_gdb_stdlog_ptr): Declare.
	(gdb_stdout, gdb_stdin, gdb_stderr, gdb_stdlog): Reimplement as
	macros.
---
 gdb/main.c  |  4 ----
 gdb/top.c   | 15 +++++++++++++++
 gdb/top.h   | 17 +++++++++++++++++
 gdb/utils.h | 19 ++++++++++++++-----
 4 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/gdb/main.c b/gdb/main.c
index c6c702c..03d6bbd 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -68,10 +68,6 @@ static int gdb_datadir_provided = 0;
    the possibly relocated path to python's lib directory.  */
 char *python_libdir = 0;
 
-struct ui_file *gdb_stdout;
-struct ui_file *gdb_stderr;
-struct ui_file *gdb_stdlog;
-struct ui_file *gdb_stdin;
 /* Target IO streams.  */
 struct ui_file *gdb_stdtargin;
 struct ui_file *gdb_stdtarg;
diff --git a/gdb/top.c b/gdb/top.c
index cae90d6..a34635b 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -86,6 +86,21 @@ extern void initialize_all_files (void);
 #define DEFAULT_PROMPT	"(gdb) "
 #endif
 
+/* Generate a function that exports a pointer to a field of the
+   current UI.  */
+
+#define gen_ret_current_ui_field_ptr(type, name)	\
+type *							\
+current_ui_## name ## _ptr (void)			\
+{							\
+  return &current_ui->m_ ## name;		\
+}
+
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdout)
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdin)
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stderr)
+gen_ret_current_ui_field_ptr (struct ui_file *, gdb_stdlog)
+
 /* Initialization file name for gdb.  This is host-dependent.  */
 
 const char gdbinit[] = GDBINIT;
diff --git a/gdb/top.h b/gdb/top.h
index fc4e90a..d404427 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -49,6 +49,23 @@ struct ui
   /* The function to invoke when a complete line of input is ready for
      processing.  */
   void (*input_handler) (char *);
+
+  /* The fields below that start with "m_" are "private".  They're
+     meant to be accessed through wrapper macros that make them look
+     like globals.  */
+
+  /* The ui_file streams.  */
+  /* Normal results */
+  struct ui_file *m_gdb_stdout;
+  /* Input stream */
+  struct ui_file *m_gdb_stdin;
+  /* Serious error notifications */
+  struct ui_file *m_gdb_stderr;
+  /* Log/debug/trace messages that should bypass normal stdout/stderr
+     filtering.  For moment, always call this stream using
+     *_unfiltered.  In the very near future that restriction shall be
+     removed - either call shall be unfiltered.  (cagney 1999-06-13).  */
+  struct ui_file *m_gdb_stdlog;
 };
 
 extern struct ui *current_ui;
diff --git a/gdb/utils.h b/gdb/utils.h
index 87bb9c0..6080f5b 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -159,18 +159,27 @@ extern void reinitialize_more_filter (void);
 
 extern int pagination_enabled;
 
-/* Global ui_file streams.  These are all defined in main.c.  */
+extern struct ui_file **current_ui_gdb_stdout_ptr (void);
+extern struct ui_file **current_ui_gdb_stdin_ptr (void);
+extern struct ui_file **current_ui_gdb_stderr_ptr (void);
+extern struct ui_file **current_ui_gdb_stdlog_ptr (void);
+
+/* The current top level's ui_file streams.  */
+
 /* Normal results */
-extern struct ui_file *gdb_stdout;
+#define gdb_stdout (*current_ui_gdb_stdout_ptr ())
 /* Input stream */
-extern struct ui_file *gdb_stdin;
+#define gdb_stdin (*current_ui_gdb_stdin_ptr ())
 /* Serious error notifications */
-extern struct ui_file *gdb_stderr;
+#define gdb_stderr (*current_ui_gdb_stderr_ptr ())
 /* Log/debug/trace messages that should bypass normal stdout/stderr
    filtering.  For moment, always call this stream using
    *_unfiltered.  In the very near future that restriction shall be
    removed - either call shall be unfiltered.  (cagney 1999-06-13).  */
-extern struct ui_file *gdb_stdlog;
+#define gdb_stdlog (*current_ui_gdb_stdlog_ptr ())
+
+/* Truly global ui_file streams.  These are all defined in main.c.  */
+
 /* Target output that should bypass normal stdout/stderr filtering.
    For moment, always call this stream using *_unfiltered.  In the
    very near future that restriction shall be removed - either call
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 25/34] Only send sync execution command output to the UI that ran the command
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (19 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 10/34] Make input_fd be per UI Pedro Alves
@ 2016-05-06 12:43 ` Pedro Alves
  2016-05-06 12:43 ` [PATCH v3 28/34] Make stdin be per UI Pedro Alves
                   ` (14 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:43 UTC (permalink / raw)
  To: gdb-patches

Currently when a "step", "next", etc. finishes, the current source
line is printed on all console UIs.

This patch makes the CLI and TUI interpreters reuse MI's logic to only
emit console output related to a synchronous command on the
console-like interpreter that started the command in the first place.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-interp.c (cli_on_normal_stop): Bail out early if there's
	nothing to print.  Use should_print_stop_to_console.
	* tui/tui-interp.c (tui_on_normal_stop): Likewise.
---
 gdb/cli/cli-interp.c | 10 ++++++++--
 gdb/tui/tui-interp.c | 11 +++++++++--
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index e6f104b..440f286 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -95,14 +95,20 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame)
 {
   struct switch_thru_all_uis state;
 
+  if (!print_frame)
+    return;
+
   SWITCH_THRU_ALL_UIS (state)
     {
-      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+      struct interp *interp = top_level_interpreter ();
+      struct cli_interp *cli = as_cli_interp (interp);
+      struct thread_info *thread;
 
       if (cli == NULL)
 	continue;
 
-      if (print_frame)
+      thread = inferior_thread ();
+      if (should_print_stop_to_console (interp, thread))
 	print_stop_event (cli->cli_uiout);
     }
 }
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 950345c..132e2e9 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -32,6 +32,7 @@
 #include "tui/tui-io.h"
 #include "infrun.h"
 #include "observer.h"
+#include "gdbthread.h"
 
 static struct ui_out *tui_ui_out (struct interp *self);
 
@@ -71,14 +72,20 @@ tui_on_normal_stop (struct bpstats *bs, int print_frame)
 {
   struct switch_thru_all_uis state;
 
+  if (!print_frame)
+    return;
+
   SWITCH_THRU_ALL_UIS (state)
     {
-      struct interp *tui = as_tui_interp (top_level_interpreter ());
+      struct interp *interp = top_level_interpreter ();
+      struct interp *tui = as_tui_interp (interp);
+      struct thread_info *thread;
 
       if (tui == NULL)
 	continue;
 
-      if (print_frame)
+      thread = inferior_thread ();
+      if (should_print_stop_to_console (interp, thread))
 	print_stop_event (tui_ui_out (tui));
     }
 }
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 27/34] Handle UI's terminal closing
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (28 preceding siblings ...)
  2016-05-06 12:45 ` [PATCH v3 26/34] Make main_ui be heap allocated Pedro Alves
@ 2016-05-06 12:45 ` Pedro Alves
  2016-05-06 12:45 ` [PATCH v3 34/34] Always switch fork child to the main UI Pedro Alves
                   ` (5 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:45 UTC (permalink / raw)
  To: gdb-patches

Without this, GDB exits if a secondary UIs terminal/input stream is
closed:

 $ ./gdb -ex "new-ui mi /dev/pts/6"
 New UI allocated
	 <<< close /dev/pts/6
 (gdb) Error detected on fd 9
 $

We want that for the main UI, but not secondary UIs.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-top.c (stdin_event_handler): Don't quit gdb if it was a
	secondary UI's input stream that closed.  Instead, just delete the
	UI.
---
 gdb/event-top.c | 42 +++++++++++++++++++++++++++---------------
 gdb/top.c       | 31 +++++++++++++++++++++++++++++++
 gdb/top.h       |  1 +
 3 files changed, 59 insertions(+), 15 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 318da1d..777823e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -508,33 +508,45 @@ stdin_event_handler (int error, gdb_client_data client_data)
 {
   struct ui *ui = (struct ui *) client_data;
 
-  /* Switch to the UI whose input descriptor woke up the event
-     loop.  */
-  current_ui = ui;
-
   if (error)
     {
-      printf_unfiltered (_("error detected on stdin\n"));
+      /* Switch to the main UI, so diagnostics always go there.  */
+      current_ui = main_ui;
+
       delete_file_handler (ui->input_fd);
-      /* If stdin died, we may as well kill gdb.  */
-      quit_command ((char *) 0, stdin == ui->instream);
+      if (main_ui == ui)
+	{
+	  /* If stdin died, we may as well kill gdb.  */
+	  printf_unfiltered (_("error detected on stdin\n"));
+	  quit_command ((char *) 0, stdin == ui->instream);
+	}
+      else
+	{
+	  /* Simply delete the UI.  */
+	  delete_ui (ui);
+	}
     }
   else
     {
-    /* This makes sure a ^C immediately followed by further input is
-       always processed in that order.  E.g,. with input like
-       "^Cprint 1\n", the SIGINT handler runs, marks the async signal
-       handler, and then select/poll may return with stdin ready,
-       instead of -1/EINTR.  The
-       gdb.base/double-prompt-target-event-error.exp test exercises
-       this.  */
+      /* Switch to the UI whose input descriptor woke up the event
+	 loop.  */
+      current_ui = ui;
+
+      /* This makes sure a ^C immediately followed by further input is
+	 always processed in that order.  E.g,. with input like
+	 "^Cprint 1\n", the SIGINT handler runs, marks the async
+	 signal handler, and then select/poll may return with stdin
+	 ready, instead of -1/EINTR.  The
+	 gdb.base/double-prompt-target-event-error.exp test exercises
+	 this.  */
       QUIT;
 
       do
 	{
 	  call_stdin_event_handler_again_p = 0;
 	  ui->call_readline (client_data);
-	} while (call_stdin_event_handler_again_p != 0);
+	}
+      while (call_stdin_event_handler_again_p != 0);
     }
 }
 
diff --git a/gdb/top.c b/gdb/top.c
index c5e237d..5883875 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -286,6 +286,37 @@ new_ui (FILE *instream, FILE *outstream, FILE *errstream)
   return ui;
 }
 
+static void
+free_ui (struct ui *ui)
+{
+  ui_file_delete (ui->m_gdb_stdin);
+  ui_file_delete (ui->m_gdb_stdout);
+  ui_file_delete (ui->m_gdb_stderr);
+
+  xfree (ui);
+}
+
+void
+delete_ui (struct ui *todel)
+{
+  struct ui *ui, *uiprev;
+
+  uiprev = NULL;
+
+  for (ui = ui_list; ui != NULL; uiprev = ui, ui = ui->next)
+    if (ui == todel)
+      break;
+
+  gdb_assert (ui != NULL);
+
+  if (uiprev != NULL)
+    uiprev->next = ui->next;
+  else
+    ui_list = ui->next;
+
+  free_ui (ui);
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
diff --git a/gdb/top.h b/gdb/top.h
index c933d6b..a0fa391 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -175,6 +175,7 @@ extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
 
 /* Create a new UI.  */
 extern struct ui *new_ui (FILE *instream, FILE *outstream, FILE *errstream);
+extern void delete_ui (struct ui *todel);
 
 /* Cleanup that restores the current UI.  */
 extern void restore_ui_cleanup (void *data);
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 26/34] Make main_ui be heap allocated
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (27 preceding siblings ...)
  2016-05-06 12:45 ` [PATCH v3 22/34] Fix for spurious prompts in secondary UIs Pedro Alves
@ 2016-05-06 12:45 ` Pedro Alves
  2016-05-06 12:45 ` [PATCH v3 27/34] Handle UI's terminal closing Pedro Alves
                   ` (6 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:45 UTC (permalink / raw)
  To: gdb-patches

This is preparation for being able to create more than one UI object.

The change to gdb_main to stop using catch_errors is necessary because
catch_errors references current_uiout, which expands to
current_ui->m_current_ui, which would crash because current_ui is not
initialized yet at that point.  It didn't trigger earlier in the
series because before this patch, main_ui/current_ui always start out
non-NULL.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* event-top.c (main_ui_): Delete.
	(main_ui, current_ui, ui_list): No longer initialize here.
	* main.c (captured_main): UI initialization code factored out to
	new new_ui function.
	(gdb_main): Wrap captured_main with TRY/CATCH instead of
	catch_errors.
	* top.c (highest_ui_num): New global.
	(new_ui): New function.
	* top.h (struct ui) <num>: New field.
	(new_ui): New declaration.
---
 gdb/event-top.c |  9 ++++-----
 gdb/main.c      | 27 ++++++++++++---------------
 gdb/top.c       | 40 ++++++++++++++++++++++++++++++++++++++++
 gdb/top.h       |  6 ++++++
 4 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index c9e7548..318da1d 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -441,12 +441,11 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-/* The main UI.  */
-static struct ui main_ui_;
+/* See top.h.  */
 
-struct ui *main_ui = &main_ui_;
-struct ui *current_ui = &main_ui_;
-struct ui *ui_list = &main_ui_;
+struct ui *main_ui;
+struct ui *current_ui;
+struct ui *ui_list;
 
 /* See top.h.  */
 
diff --git a/gdb/main.c b/gdb/main.c
index 541a077..8c9d563 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -443,7 +443,6 @@ DEF_VEC_O (cmdarg_s);
 static int
 captured_main (void *data)
 {
-  struct ui *ui = current_ui;
   struct captured_main_args *context = (struct captured_main_args *) data;
   int argc = context->argc;
   char **argv = context->argv;
@@ -514,26 +513,15 @@ captured_main (void *data)
 
   saved_command_line = (char *) xstrdup ("");
 
-  ui->instream = stdin;
-  ui->outstream = stdout;
-  ui->errstream = stderr;
-
-  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.  */
   setvbuf (stderr, NULL, _IONBF, BUFSIZ);
 #endif
 
-  gdb_stdout = stdio_fileopen (stdout);
-  gdb_stderr = stderr_fileopen (stderr);
+  main_ui = new_ui (stdin, stdout, stderr);
+  current_ui = main_ui;
 
-  gdb_stdlog = gdb_stderr;	/* for moment */
-  gdb_stdtarg = gdb_stderr;	/* for moment */
-  gdb_stdin = stdio_fileopen (stdin);
   gdb_stdtargerr = gdb_stderr;	/* for moment */
   gdb_stdtargin = gdb_stdin;	/* for moment */
 
@@ -1174,7 +1162,16 @@ captured_main (void *data)
 int
 gdb_main (struct captured_main_args *args)
 {
-  catch_errors (captured_main, args, "", RETURN_MASK_ALL);
+  TRY
+    {
+      captured_main (args);
+    }
+  CATCH (ex, RETURN_MASK_ALL)
+    {
+      exception_print (gdb_stderr, ex);
+    }
+  END_CATCH
+
   /* The only way to end up here is by an error (normal exit is
      handled by quit_force()), hence always return an error status.  */
   return 1;
diff --git a/gdb/top.c b/gdb/top.c
index e40835b..c5e237d 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -246,6 +246,46 @@ void (*deprecated_call_command_hook) (struct cmd_list_element * c,
 
 void (*deprecated_context_hook) (int id);
 
+/* The highest UI number ever assigned.  */
+static int highest_ui_num;
+
+/* See top.h.  */
+
+struct ui *
+new_ui (FILE *instream, FILE *outstream, FILE *errstream)
+{
+  struct ui *ui;
+
+  ui = XCNEW (struct ui);
+
+  ui->num = ++highest_ui_num;
+  ui->instream = instream;
+  ui->outstream = outstream;
+  ui->errstream = errstream;
+
+  ui->input_fd = fileno (ui->instream);
+
+  ui->m_gdb_stdin = stdio_fileopen (ui->instream);
+  ui->m_gdb_stdout = stdio_fileopen (ui->outstream);
+  ui->m_gdb_stderr = stderr_fileopen (ui->errstream);
+  ui->m_gdb_stdlog = ui->m_gdb_stderr;
+
+  ui->prompt_state = PROMPT_NEEDED;
+
+  if (ui_list == NULL)
+    ui_list = ui;
+  else
+    {
+      struct ui *last;
+
+      for (last = ui_list; last->next != NULL; last = last->next)
+	;
+      last->next = ui;
+    }
+
+  return ui;
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
diff --git a/gdb/top.h b/gdb/top.h
index 092cc26..c933d6b 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -57,6 +57,9 @@ struct ui
   /* Pointer to next in singly-linked list.  */
   struct ui *next;
 
+  /* Convenient handle (UI number).  Unique across all UIs.  */
+  int num;
+
   /* The UI's command line buffer.  This is to used to accumulate
      input until we have a whole command line.  */
   struct buffer line_buffer;
@@ -170,6 +173,9 @@ extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
 #define ALL_UIS(UI)				\
   for (UI = ui_list; UI; UI = UI->next)		\
 
+/* Create a new UI.  */
+extern struct ui *new_ui (FILE *instream, FILE *outstream, FILE *errstream);
+
 /* Cleanup that restores the current UI.  */
 extern void restore_ui_cleanup (void *data);
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 34/34] Always switch fork child to the main UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (29 preceding siblings ...)
  2016-05-06 12:45 ` [PATCH v3 27/34] Handle UI's terminal closing Pedro Alves
@ 2016-05-06 12:45 ` Pedro Alves
  2016-05-06 12:52 ` [PATCH v3 18/34] Make raw_stdout be per MI instance Pedro Alves
                   ` (4 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:45 UTC (permalink / raw)
  To: gdb-patches

The following scenario:

 - gdb started in normal cli mode.

 - separate MI channel created with MI

 - inferior output redirected with the "set inferior-tty" command.

 - use -exec-run in the MI channel to run the inferior

is presently mishandled.

When we create the inferior, in fork-child.c, right after vfork, we'll
close all the file descriptors in the vfork child, and then dup the
tty to file descriptors 0/1/2, create a session, etc.  Note that when
we close all descriptors, we close the file descriptors behind
gdb_stdin/gdb_stdout/gdb_stderr of all secondary UIs...  So if
anything goes wrong in the child and it calls warning/error, it'll end
up writting to the current UI's stdout/stderr streams, which are
backed by file descriptors that have since been closed.  Because this
happens in a vfork region, the corresponding stdin/stdout/stderr in
the parent/gdb end up corrupted.

The fix is to switch to the main UI right after the vfork, so that
gdb_stdin/gdb_stdout/gdb_stderr are correctly mapped to
stdin/stdout/stderr (and thus to file descriptors 0/1/2), so this code
works as it has always worked.

(Technically, we're doing a lot of stuff we shouldn't be doing after a
vfork, while we should only be calling async-signal-safe functions.)

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* fork-child.c (fork_inferior): Switch the child to the main UI
	right after vfork.  Save/restore the current UI in the parent.
	Flush outputs of the main UI instead of the current UI.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.mi/mi-exec-run.exp: New file.
---
 gdb/fork-child.c                     |  22 ++++-
 gdb/testsuite/gdb.mi/mi-exec-run.exp | 158 +++++++++++++++++++++++++++++++++++
 2 files changed, 178 insertions(+), 2 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-exec-run.exp

diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index 204b7cf..8ac3bef 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -31,6 +31,7 @@
 #include "gdbcmd.h"
 #include "solib.h"
 #include "filestuff.h"
+#include "top.h"
 
 #include <signal.h>
 
@@ -141,6 +142,7 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
   struct inferior *inf;
   int i;
   int save_errno;
+  struct ui *save_ui;
 
   /* If no exec file handed to us, get it from the exec-file command
      -- with a good, common error message if none is specified.  */
@@ -275,6 +277,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
      restore it.  */
   save_our_env = environ;
 
+  /* Likewise the current UI.  */
+  save_ui = current_ui;
+
   /* Tell the terminal handling subsystem what tty we plan to run on;
      it will just record the information for later.  */
   new_tty_prefork (inferior_io_terminal);
@@ -282,8 +287,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
   /* It is generally good practice to flush any possible pending stdio
      output prior to doing a fork, to avoid the possibility of both
      the parent and child flushing the same data after the fork.  */
-  gdb_flush (gdb_stdout);
-  gdb_flush (gdb_stderr);
+  gdb_flush (main_ui->m_gdb_stdout);
+  gdb_flush (main_ui->m_gdb_stderr);
 
   /* If there's any initialization of the target layers that must
      happen to prepare to handle the child we're about fork, do it
@@ -312,6 +317,16 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
 
   if (pid == 0)
     {
+      /* Switch to the main UI, so that gdb_std{in/out/err} in the
+	 child are mapped to std{in/out/err}.  This makes it possible
+	 to use fprintf_unfiltered/warning/error/etc. in the child
+	 from here on.  */
+      current_ui = main_ui;
+
+      /* Close all file descriptors except those that gdb inherited
+	 (usually 0/1/2), so they don't leak to the inferior.  Note
+	 that this closes the file descriptors of all secondary
+	 UIs.  */
       close_most_fds ();
 
       if (debug_fork)
@@ -378,6 +393,9 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
   /* Restore our environment in case a vforked child clob'd it.  */
   environ = save_our_env;
 
+  /* Likewise the current UI.  */
+  current_ui = save_ui;
+
   if (!have_inferiors ())
     init_thread_list ();
 
diff --git a/gdb/testsuite/gdb.mi/mi-exec-run.exp b/gdb/testsuite/gdb.mi/mi-exec-run.exp
new file mode 100644
index 0000000..a550a7f
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-exec-run.exp
@@ -0,0 +1,158 @@
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test that -exec-run works as expected.  Exercises various testing
+# axes:
+#
+# - MI running on main UI vs separate UI.
+#
+# - inferior tty set to main tty vs separate tty.
+#
+# - forking the child failing and sending output to the right inferior
+#   terminal, vs the child not failing to start.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+# The purpose of this testcase is to test the -exec-run command. If we
+# cannot use it, then there is no point in running this testcase.
+if [target_info exists use_gdb_stub] {
+     untested "cannot use -exec-run command"
+     return -1
+}
+
+standard_testfile mi-start.c
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     untested "could not build mi-exec-run"
+     return -1
+}
+
+# The test proper.  INFTTY_MODE determines whether "set inferior-tty"
+# is in effect.  MI_MODE determines whether MI is run on the main UI,
+# or as a separate UI.  FORCE_FAIL is true when we want -exec-run to
+# fail and cause inferior output be sent to the inferior tty.
+
+proc test {inftty_mode mi_mode force_fail} {
+    global srcdir subdir binfile srcfile
+    global gdb_spawn_id gdb_main_spawn_id mi_spawn_id inferior_spawn_id
+    global decimal
+
+    mi_gdb_exit
+
+    set start_ops {}
+    if {$inftty_mode == "separate"} {
+	lappend start_ops "separate-inferior-tty"
+    }
+    if {$mi_mode == "separate"} {
+	lappend start_ops "separate-mi-tty"
+    }
+
+    if [eval mi_gdb_start $start_ops] {
+	return
+    }
+
+    if {$force_fail} {
+	# Disable the shell so that its the first exec that fails,
+	# instead of the shell starting and then failing with some
+	# unspecified output.
+	mi_gdb_test "-gdb-set startup-with-shell off" ".*"
+	set bin $binfile.nox
+    } else {
+	set bin $binfile
+    }
+
+    mi_delete_breakpoints
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_load ${bin}
+
+    # Useful for debugging:
+    verbose -log "Channels:"
+    verbose -log " inferior_spawn_id=$inferior_spawn_id"
+    verbose -log " gdb_spawn_id=$gdb_spawn_id"
+    verbose -log " gdb_main_spawn_id=$gdb_main_spawn_id"
+    verbose -log " mi_spawn_id=$mi_spawn_id"
+
+    if {$force_fail} {
+	set saw_perm_error 0
+	set saw_mi_error 0
+	set test "run failure detected"
+	send_gdb "-exec-run --start\n"
+
+	while {1} {
+	    gdb_expect {
+		-i "$inferior_spawn_id"
+		-re ".*Cannot exec.*Permission denied" {
+		    set saw_perm_error 1
+		    verbose -log "saw mi error"
+		}
+		-i "$gdb_spawn_id"
+		-re "\\^error,msg=\"During startup program exited with code 127" {
+		    set saw_mi_error 1
+		    verbose -log "saw mi error"
+		}
+		timeout {
+		    fail "$test (timeout)"
+		    break
+		}
+		-i "$gdb_main_spawn_id"
+		eof {
+		    fail "$test (eof)"
+		    break
+		}
+	    }
+
+	    if {$saw_perm_error && $saw_mi_error} {
+		pass $test
+		break
+	    }
+	}
+    } else {
+	mi_run_cmd "--start"
+	mi_expect_stop "breakpoint-hit" "main" "" ".*$srcfile" "$decimal" \
+	    { "" "disp=\"del\"" } "breakpoint hit reported on mi"
+
+	if {$mi_mode == "separate"} {
+	    # Check that the breakpoint hit is reported on the main
+	    # UI/CLI.  Note no prompt is expected.
+	    switch_gdb_spawn_id $gdb_main_spawn_id
+
+	    set test "breakpoint hit reported on console"
+	    gdb_test_multiple "" $test {
+		-re "Temporary breakpoint .*, main \\(\\) at .*$srcfile:$decimal.*return 0;" {
+		    pass $test
+		}
+	    }
+
+	    # Switch back to the MI UI.
+	    global mi_spawn_id
+	    switch_gdb_spawn_id $mi_spawn_id
+	}
+    }
+}
+
+# Create a not-executable copy of the program, in order to exercise
+# vfork->exec failing.
+gdb_remote_download host $binfile $binfile.nox
+remote_spawn target "chmod \"a-x\" $binfile.nox"
+
+foreach_with_prefix inferior-tty {"main" "separate"} {
+    foreach_with_prefix mi {"main" "separate"} {
+	foreach_with_prefix force-fail {0 1} {
+	    test ${inferior-tty} ${mi} ${force-fail}
+	}
+    }
+}
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 32/34] Send deleted watchpoint-scope output to all UIs
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (25 preceding siblings ...)
  2016-05-06 12:43 ` [PATCH v3 07/34] Make the intepreters output to all UIs Pedro Alves
@ 2016-05-06 12:45 ` Pedro Alves
  2016-05-06 12:45 ` [PATCH v3 22/34] Fix for spurious prompts in secondary UIs Pedro Alves
                   ` (8 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:45 UTC (permalink / raw)
  To: gdb-patches

Testing with:

  make check RUNTESTFLAGS="SEPARATE_MI_TTY=1"

shows this, in gdb.mi/mi-watch.exp:

 -*stopped,reason="watchpoint-scope",wpnum="2",frame={addr="0x00000000004005cb",
 +*stopped,frame={addr="0x00000000004005cb",
 (...)
 -PASS: gdb.mi/mi-watch.exp: hw: watchpoint trigger
 +FAIL: gdb.mi/mi-watch.exp: hw: watchpoint trigger (unknown output after running)

That is, we lose the "watchpoint-scope" output on the MI UI.

This commit fixes it, and makes the test run with MI running as both
main UI and separate UI.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* breakpoint.c (watchpoint_check): Send watchpoint-deleted output
	to all UIs.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.mi/mi-watch.exp (test_watchpoint_creation_and_listing)
	(test_awatch_creation_and_listing)
	(test_rwatch_creation_and_listing, test_watchpoint_triggering):
	Remove 'type' parameter.
	(test_watchpoint_all): New parameter mi_mode.  Remove
	with_test_prefix.
	(top level): Use foreach_with_prefix, and add main/separate UI MI
	testing axis.
---
 gdb/breakpoint.c                  | 40 ++++++++++++------
 gdb/testsuite/gdb.mi/mi-watch.exp | 85 ++++++++++++++++++++-------------------
 2 files changed, 71 insertions(+), 54 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index d181597..b2da81b 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5240,7 +5240,7 @@ watchpoint_check (void *p)
     }
   else
     {
-      struct ui_out *uiout = current_uiout;
+      struct switch_thru_all_uis state;
 
       /* This seems like the only logical thing to do because
          if we temporarily ignored the watchpoint, then when
@@ -5255,14 +5255,20 @@ watchpoint_check (void *p)
 	 call breakpoint_ops->print_it this bp will be deleted
 	 already.  So we have no choice but print the information
 	 here.  */
-      if (ui_out_is_mi_like_p (uiout))
-	ui_out_field_string
-	  (uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE));
-      ui_out_text (uiout, "\nWatchpoint ");
-      ui_out_field_int (uiout, "wpnum", b->base.number);
-      ui_out_text (uiout,
-		   " deleted because the program has left the block in\n\
-which its expression is valid.\n");     
+
+      SWITCH_THRU_ALL_UIS (state)
+        {
+	  struct ui_out *uiout = current_uiout;
+
+	  if (ui_out_is_mi_like_p (uiout))
+	    ui_out_field_string
+	      (uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE));
+	  ui_out_text (uiout, "\nWatchpoint ");
+	  ui_out_field_int (uiout, "wpnum", b->base.number);
+	  ui_out_text (uiout,
+		       " deleted because the program has left the block in\n"
+		       "which its expression is valid.\n");
+	}
 
       /* Make sure the watchpoint's commands aren't executed.  */
       decref_counted_command_line (&b->base.commands);
@@ -5430,10 +5436,18 @@ bpstat_check_watchpoint (bpstat bs)
 	      /* Can't happen.  */
 	    case 0:
 	      /* Error from catch_errors.  */
-	      printf_filtered (_("Watchpoint %d deleted.\n"), b->base.number);
-	      watchpoint_del_at_next_stop (b);
-	      /* We've already printed what needs to be printed.  */
-	      bs->print_it = print_it_done;
+	      {
+		struct switch_thru_all_uis state;
+
+		SWITCH_THRU_ALL_UIS (state)
+	          {
+		    printf_filtered (_("Watchpoint %d deleted.\n"),
+				     b->base.number);
+		  }
+		watchpoint_del_at_next_stop (b);
+		/* We've already printed what needs to be printed.  */
+		bs->print_it = print_it_done;
+	      }
 	      break;
 	    }
 	}
diff --git a/gdb/testsuite/gdb.mi/mi-watch.exp b/gdb/testsuite/gdb.mi/mi-watch.exp
index f4b54bb..29fc471 100644
--- a/gdb/testsuite/gdb.mi/mi-watch.exp
+++ b/gdb/testsuite/gdb.mi/mi-watch.exp
@@ -24,9 +24,6 @@ load_lib mi-support.exp
 set MIFLAGS "-i=mi"
 
 gdb_exit
-if [mi_gdb_start] {
-    continue
-}
 
 standard_testfile basics.c
 
@@ -35,7 +32,7 @@ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb
      return -1
 }
 
-proc test_watchpoint_creation_and_listing {type} {
+proc test_watchpoint_creation_and_listing {} {
     global mi_gdb_prompt
     global srcfile
     global hex
@@ -59,7 +56,7 @@ proc test_watchpoint_creation_and_listing {type} {
 }
 
 # UNUSED at the time
-proc test_awatch_creation_and_listing {type} {
+proc test_awatch_creation_and_listing {} {
     global mi_gdb_prompt
     global srcfile
     global hex
@@ -86,7 +83,7 @@ proc test_awatch_creation_and_listing {type} {
 }
 
 # UNUSED at the time
-proc test_rwatch_creation_and_listing {type} {
+proc test_rwatch_creation_and_listing {} {
     global mi_gdb_prompt
     global srcfile
     global hex
@@ -112,7 +109,7 @@ proc test_rwatch_creation_and_listing {type} {
 	    "delete read watchpoint"
 }
 
-proc test_watchpoint_triggering {type} {
+proc test_watchpoint_triggering {} {
     global mi_gdb_prompt
     global hex fullname_syntax srcfile
 
@@ -137,44 +134,50 @@ proc test_watchpoint_triggering {type} {
         "watchpoint trigger"
 }
 
-proc test_watchpoint_all {type} {
-    with_test_prefix "$type" {
-	upvar srcdir srcdir
-	upvar subdir subdir
-	upvar binfile binfile
-
-	mi_delete_breakpoints
-	mi_gdb_reinitialize_dir $srcdir/$subdir
-	mi_gdb_load ${binfile}
-
-	mi_runto callee4
-	test_watchpoint_creation_and_listing $type
-	#test_rwatch_creation_and_listing $type
-	#test_awatch_creation_and_listing $type
-	test_watchpoint_triggering $type
+proc test_watchpoint_all {mi_mode type} {
+    upvar srcdir srcdir
+    upvar subdir subdir
+    upvar binfile binfile
+
+    if {$type == "hw" && [target_info exists gdb,no_hardware_watchpoints] } {
+	return
     }
-}
 
-# Run the tests twice, once using software watchpoints...
-mi_gdb_test "567-gdb-set can-use-hw-watchpoints 0" \
-	"567\\^done" \
-	"hw watchpoints toggle (1)"
-test_watchpoint_all sw
+    mi_gdb_exit
 
-mi_gdb_exit
+    if {$mi_mode == "separate"} {
+	set start_ops "separate-mi-tty"
+    } else {
+	set start_ops ""
+    }
+    if [mi_gdb_start $start_ops] {
+	return
+    }
 
-# ... and unless requested otherwise...
-if [target_info exists gdb,no_hardware_watchpoints] {
-    return 0
-}
+    if {$type == "sw"} {
+	set option 0
+    } else {
+	set option 1
+    }
+    mi_gdb_test "567-gdb-set can-use-hw-watchpoints $option" \
+	"567\\^done" \
+	"hw watchpoints toggle"
 
-mi_gdb_start
+    mi_delete_breakpoints
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_load ${binfile}
 
-# ... once using hardware watchpoints (if available).
-mi_gdb_test "890-gdb-set can-use-hw-watchpoints 1" \
-	"890\\^done" \
-	"hw watchpoints toggle (2)"
-test_watchpoint_all hw
+    mi_runto callee4
+    test_watchpoint_creation_and_listing
+    #test_rwatch_creation_and_listing
+    #test_awatch_creation_and_listing
+    test_watchpoint_triggering
+}
 
-mi_gdb_exit
-return 0
+# Run the tests twice, once using software watchpoints, and another
+# with hardware watchpoints.
+foreach_with_prefix mi-mode {"main" "separate"} {
+    foreach_with_prefix wp-type {"sw" "hw"} {
+	test_watchpoint_all ${mi-mode} ${wp-type}
+    }
+}
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 22/34] Fix for spurious prompts in secondary UIs
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (26 preceding siblings ...)
  2016-05-06 12:45 ` [PATCH v3 32/34] Send deleted watchpoint-scope " Pedro Alves
@ 2016-05-06 12:45 ` Pedro Alves
  2016-05-06 12:45 ` [PATCH v3 26/34] Make main_ui be heap allocated Pedro Alves
                   ` (7 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:45 UTC (permalink / raw)
  To: gdb-patches

Running mi-break.exp with MI on a secondary UI reveals that MI emits
spurious prompts compared MI running as primary UI:

   -exec-continue
   ^running
   *running,thread-id="all"
   (gdb)
   =breakpoint-modified,bkpt={number="9",type="breakpoint",disp="keep",enabled="y",func="callee2",line="39",script={"set $i=0","while $i<10","print $i","set $i=$i+1","end","continue"}}
   ~"\n"
   ~"Breakpoint 9, callee2 (intarg=2, strarg=0x400730 \"A string argument.\") at ...src/gdb/testsuite/gdb.mi/basics.c:39\n"
   ~"39\t  callee3 (strarg);\n"
   *stopped,reason="breakpoint-hit",disp="keep",bkptno="9",frame={addr="0x00000000004005dd",func="callee2",...
   *running,thread-id="all"
>> (gdb)
   =breakpoint-modified,bkpt={number="9",...
   ~"\n"
   ~"Breakpoint 9, callee2 (intarg=2, strarg=0x400730 \"A string argument.\") at ...src/gdb/testsuite/gdb.mi/basics.c:39\n"
   ~"39\t  callee3 (strarg);\n"
   *stopped,reason="breakpoint-hit",disp="keep",bkptno="9",...
   *running,thread-id="all"
   ~"[Inferior 1 (process 12639) exited normally]\n"
   =thread-exited,id="1",group-id="i1"
   =thread-group-exited,id="i1",exit-code="0"
   *stopped,reason="exited-normally"
   FAIL: gdb.mi/mi-break.exp: intermediate stop and continue
   FAIL: gdb.mi/mi-break.exp: test hitting breakpoint with commands (timeout)

Note the line marked >> above.

The test sets a breakpoint that runs "continue", a foreground command.
When we get to run the "continue", we've already emitted the *stopped
event on the MI UI, and set its prompt state to PROMPT_NEEDED (this is
done from within normal_stop).  Since inferior events are always
handled with the main UI as current UI, breakpoint commands always run
with the main UI as current UI too.  This means that the "continue"
ends up always disabling the prompt on the main UI, instead of the UI
that had just been done with synchronous execution.

I think we'll want to extend this with a concept of "set of
threads/inferiors a UI/interpreter is blocked waiting on", but I'm
leaving that for a separate series.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* infcmd.c (prepare_execution_command): Use
	all_uis_on_sync_execution_starting.
	* infrun.c (all_uis_on_sync_execution_starting): New function.
	* infrun.h (all_uis_on_sync_execution_starting): Declare.
---
 gdb/infcmd.c |  2 +-
 gdb/infrun.c | 14 ++++++++++++++
 gdb/infrun.h |  5 +++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 813d11a..a1d4d5d 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -510,7 +510,7 @@ prepare_execution_command (struct target_ops *target, int background)
 	 simulate synchronous (fg) execution.  Note no cleanup is
 	 necessary for this.  stdin is re-enabled whenever an error
 	 reaches the top level.  */
-      async_disable_stdin ();
+      all_uis_on_sync_execution_starting ();
     }
 }
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b9b32c9..cc793c3 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3877,6 +3877,20 @@ all_uis_check_sync_execution_done (void)
     }
 }
 
+/* See infrun.h.  */
+
+void
+all_uis_on_sync_execution_starting (void)
+{
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      if (current_ui->prompt_state == PROMPT_NEEDED)
+	async_disable_stdin ();
+    }
+}
+
 /* A cleanup that restores the execution direction to the value saved
    in *ARG.  */
 
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 01eff9a..39be375 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -238,4 +238,9 @@ extern void maybe_remove_breakpoints (void);
    ready for input).  */
 extern void all_uis_check_sync_execution_done (void);
 
+/* If a UI was in sync execution mode, and hasn't displayed the prompt
+   yet, re-disable its prompt (a synchronous execution command was
+   started or re-started).  */
+extern void all_uis_on_sync_execution_starting (void);
+
 #endif /* INFRUN_H */
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 18/34] Make raw_stdout be per MI instance
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (30 preceding siblings ...)
  2016-05-06 12:45 ` [PATCH v3 34/34] Always switch fork child to the main UI Pedro Alves
@ 2016-05-06 12:52 ` Pedro Alves
  2016-05-06 12:53 ` [PATCH v3 09/34] Make instream be per UI Pedro Alves
                   ` (3 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:52 UTC (permalink / raw)
  To: gdb-patches

Each MI instance should obviously have its own raw output channel,
along with save_raw_stdout.

yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* interps.c (current_interpreter): New function.
	* interps.h (current_interpreter): New declaration.
	* mi/mi-cmds.h (raw_stdout): Delete declaration.
	* mi/mi-common.h (struct mi_interp) <raw_stdout,
	saved_raw_stdout>: New field.
	* mi/mi-interp.c (display_mi_prompt): New parameter 'mi'.  Adjust
	to per-UI raw_stdout.
	(mi_interpreter_init): Adjust to per-UI raw_stdout.
	(mi_on_sync_execution_done, mi_execute_command_input_handler)
	(mi_command_loop): Pass MI instance to display_mi_prompt.
	(mi_on_normal_stop_1, mi_output_running_pid, mi_on_resume_1)
	(mi_on_resume): Adjust to per-UI raw_stdout.
	(saved_raw_stdout): Delete.
	(mi_set_logging): Adjust to per-UI raw_stdout and
	saved_raw_stdout.
	* mi/mi-main.c (raw_stdout): Delete.
	(mi_cmd_gdb_exit, captured_mi_execute_command)
	(mi_print_exception, mi_load_progress): Adjust to per-UI
	raw_stdout.
	(print_diff_now, mi_print_timing_maybe): New ui_file parameter.
	Pass it along.
	(print_diff): New ui_file parameter.  Send output there instead of
	raw_stdout.
	* mi/mi-main.h (struct ui_file): Forward declare.
	(mi_print_timing_maybe): Add ui_file parameter.
---
 gdb/interps.c      | 10 ++++++
 gdb/interps.h      |  3 ++
 gdb/mi/mi-cmds.h   |  3 --
 gdb/mi/mi-common.h |  7 ++++
 gdb/mi/mi-interp.c | 95 +++++++++++++++++++++++++-----------------------------
 gdb/mi/mi-main.c   | 93 ++++++++++++++++++++++++++++------------------------
 gdb/mi/mi-main.h   |  4 ++-
 7 files changed, 118 insertions(+), 97 deletions(-)

diff --git a/gdb/interps.c b/gdb/interps.c
index 536630a..36e0422 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -606,6 +606,16 @@ top_level_interpreter_data (void)
   return interp->data;
 }
 
+/* See interps.h.  */
+
+struct interp *
+current_interpreter (void)
+{
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
+  return ui_interp->current_interpreter;
+}
+
 /* This just adds the "interpreter-exec" command.  */
 void
 _initialize_interpreter (void)
diff --git a/gdb/interps.h b/gdb/interps.h
index 4922544..45f9bf2 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -117,6 +117,9 @@ extern int current_interp_set_logging (int start_log, struct ui_file *out,
 extern void *top_level_interpreter_data (void);
 extern struct interp *top_level_interpreter (void);
 
+/* Return the current UI's current interpreter.  */
+extern struct interp *current_interpreter (void);
+
 extern struct interp *command_interp (void);
 
 extern void clear_interpreter_hooks (void);
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index c3bc777..69472a9 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -157,9 +157,6 @@ extern struct mi_cmd *mi_lookup (const char *command);
 /* Debug flag */
 extern int mi_debug_p;
 
-/* Raw console output - FIXME: should this be a parameter? */
-extern struct ui_file *raw_stdout;
-
 extern void mi_execute_command (const char *cmd, int from_tty);
 
 #endif
diff --git a/gdb/mi/mi-common.h b/gdb/mi/mi-common.h
index 7bb706c..c7e4855 100644
--- a/gdb/mi/mi-common.h
+++ b/gdb/mi/mi-common.h
@@ -57,6 +57,13 @@ struct mi_interp
   struct ui_file *targ;
   struct ui_file *event_channel;
 
+  /* Raw console output.  */
+  struct ui_file *raw_stdout;
+
+  /* Save the original value of raw_stdout here when logging, so we
+     can restore correctly when done.  */
+  struct ui_file *saved_raw_stdout;
+
   /* MI's builder.  */
   struct ui_out *mi_uiout;
 
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index b4d498d..d4c89f7 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -91,10 +91,10 @@ static int report_initial_inferior (struct inferior *inf, void *closure);
 /* Display the MI prompt.  */
 
 static void
-display_mi_prompt (void)
+display_mi_prompt (struct mi_interp *mi)
 {
-  fputs_unfiltered ("(gdb) \n", raw_stdout);
-  gdb_flush (raw_stdout);
+  fputs_unfiltered ("(gdb) \n", mi->raw_stdout);
+  gdb_flush (mi->raw_stdout);
 }
 
 /* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and
@@ -115,20 +115,18 @@ mi_interpreter_init (struct interp *interp, int top_level)
   const char *name;
   int mi_version;
 
-  /* Assign the output channel created at startup to its own global,
-     so that we can create a console channel that encapsulates and
-     prefixes all gdb_output-type bits coming from the rest of the
-     debugger.  */
-
-  raw_stdout = gdb_stdout;
+  /* Store the current output channel, so that we can create a console
+     channel that encapsulates and prefixes all gdb_output-type bits
+     coming from the rest of the debugger.  */
+  mi->raw_stdout = gdb_stdout;
 
   /* Create MI console channels, each with a different prefix so they
      can be distinguished.  */
-  mi->out = mi_console_file_new (raw_stdout, "~", '"');
-  mi->err = mi_console_file_new (raw_stdout, "&", '"');
+  mi->out = mi_console_file_new (mi->raw_stdout, "~", '"');
+  mi->err = mi_console_file_new (mi->raw_stdout, "&", '"');
   mi->log = mi->err;
-  mi->targ = mi_console_file_new (raw_stdout, "@", '"');
-  mi->event_channel = mi_console_file_new (raw_stdout, "=", 0);
+  mi->targ = mi_console_file_new (mi->raw_stdout, "@", '"');
+  mi->event_channel = mi_console_file_new (mi->raw_stdout, "=", 0);
 
   name = interp_name (interp);
   /* INTERP_MI selects the most recent released version.  "mi2" was
@@ -308,7 +306,7 @@ mi_on_sync_execution_done (void)
   /* If MI is sync, then output the MI prompt now, indicating we're
      ready for further input.  */
   if (!mi_async_p ())
-    display_mi_prompt ();
+    display_mi_prompt (mi);
 }
 
 /* mi_execute_command_wrapper wrapper suitable for INPUT_HANDLER.  */
@@ -316,6 +314,8 @@ mi_on_sync_execution_done (void)
 static void
 mi_execute_command_input_handler (char *cmd)
 {
+  struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+
   mi_execute_command_wrapper (cmd);
 
   /* Print a prompt, indicating we're ready for further input, unless
@@ -324,18 +324,20 @@ mi_execute_command_input_handler (char *cmd)
      'synchronous_command_done' observer when the target next
      stops.  */
   if (!sync_execution)
-    display_mi_prompt ();
+    display_mi_prompt (mi);
 }
 
 static void
 mi_command_loop (void *data)
 {
+  struct mi_interp *mi = (struct mi_interp *) data;
+
   /* Turn off 8 bit strings in quoted output.  Any character with the
      high bit set is printed using C's octal format.  */
   sevenbit_strings = 1;
 
   /* Tell the world that we're alive.  */
-  display_mi_prompt ();
+  display_mi_prompt (mi);
 
   start_event_loop ();
 }
@@ -658,6 +660,7 @@ mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
      using cli interpreter, be sure to use MI uiout for output,
      not the current one.  */
   struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
+  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
 
   if (print_frame)
     {
@@ -699,12 +702,7 @@ mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
 	       && thread_fsm_finished_p (tp->thread_fsm))
 	  || (tp->control.command_interp != NULL
 	      && tp->control.command_interp != top_level_interpreter ()))
-	{
-	  struct mi_interp *mi
-	    = (struct mi_interp *) top_level_interpreter_data ();
-
-	  print_stop_event (mi->cli_uiout);
-	}
+	print_stop_event (mi->cli_uiout);
 
       tp = inferior_thread ();
       ui_out_field_int (mi_uiout, "thread-id", tp->global_num);
@@ -724,12 +722,12 @@ mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
 	ui_out_field_int (mi_uiout, "core", core);
     }
   
-  fputs_unfiltered ("*stopped", raw_stdout);
-  mi_out_put (mi_uiout, raw_stdout);
+  fputs_unfiltered ("*stopped", mi->raw_stdout);
+  mi_out_put (mi_uiout, mi->raw_stdout);
   mi_out_rewind (mi_uiout);
-  mi_print_timing_maybe ();
-  fputs_unfiltered ("\n", raw_stdout);
-  gdb_flush (raw_stdout);
+  mi_print_timing_maybe (mi->raw_stdout);
+  fputs_unfiltered ("\n", mi->raw_stdout);
+  gdb_flush (mi->raw_stdout);
 }
 
 static void
@@ -1055,7 +1053,7 @@ mi_output_running_pid (struct thread_info *info, void *arg)
 	continue;
 
       if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
-	fprintf_unfiltered (raw_stdout,
+	fprintf_unfiltered (mi->raw_stdout,
 			    "*running,thread-id=\"%d\"\n",
 			    info->global_num);
     }
@@ -1076,7 +1074,7 @@ mi_inferior_count (struct inferior *inf, void *arg)
 }
 
 static void
-mi_on_resume_1 (ptid_t ptid)
+mi_on_resume_1 (struct mi_interp *mi, ptid_t ptid)
 {
   /* To cater for older frontends, emit ^running, but do it only once
      per each command.  We do it here, since at this point we know
@@ -1088,12 +1086,12 @@ mi_on_resume_1 (ptid_t ptid)
      In future (MI3), we'll be outputting "^done" here.  */
   if (!running_result_record_printed && mi_proceeded)
     {
-      fprintf_unfiltered (raw_stdout, "%s^running\n",
+      fprintf_unfiltered (mi->raw_stdout, "%s^running\n",
 			  current_token ? current_token : "");
     }
 
   if (ptid_get_pid (ptid) == -1)
-    fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
+    fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n");
   else if (ptid_is_pid (ptid))
     {
       int count = 0;
@@ -1104,7 +1102,7 @@ mi_on_resume_1 (ptid_t ptid)
       iterate_over_inferiors (mi_inferior_count, &count);
 
       if (count == 1)
-	fprintf_unfiltered (raw_stdout, "*running,thread-id=\"all\"\n");
+	fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"all\"\n");
       else
 	iterate_over_threads (mi_output_running_pid, &ptid);
     }
@@ -1113,7 +1111,7 @@ mi_on_resume_1 (ptid_t ptid)
       struct thread_info *ti = find_thread_ptid (ptid);
 
       gdb_assert (ti);
-      fprintf_unfiltered (raw_stdout, "*running,thread-id=\"%d\"\n",
+      fprintf_unfiltered (mi->raw_stdout, "*running,thread-id=\"%d\"\n",
 			  ti->global_num);
     }
 
@@ -1126,9 +1124,9 @@ mi_on_resume_1 (ptid_t ptid)
 	 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);
+	fputs_unfiltered ("(gdb) \n", mi->raw_stdout);
     }
-  gdb_flush (raw_stdout);
+  gdb_flush (mi->raw_stdout);
 }
 
 static void
@@ -1157,7 +1155,7 @@ mi_on_resume (ptid_t ptid)
       old_chain = make_cleanup_restore_target_terminal ();
       target_terminal_ours_for_output ();
 
-      mi_on_resume_1 (ptid);
+      mi_on_resume_1 (mi, ptid);
 
       do_cleanups (old_chain);
     }
@@ -1367,11 +1365,6 @@ mi_ui_out (struct interp *interp)
   return mi->mi_uiout;
 }
 
-/* Save the original value of raw_stdout here when logging, so we can
-   restore correctly when done.  */
-
-static struct ui_file *saved_raw_stdout;
-
 /* Do MI-specific logging actions; save raw_stdout, and change all
    the consoles to use the supplied ui-file(s).  */
 
@@ -1394,23 +1387,23 @@ mi_set_logging (struct interp *interp, int start_log,
       if (logfile)
 	{
 	  ui_file_delete (out);
-	  out = tee_file_new (raw_stdout, 0, logfile, 0);
+	  out = tee_file_new (mi->raw_stdout, 0, logfile, 0);
 	}
 
-      saved_raw_stdout = raw_stdout;
-      raw_stdout = out;
+      mi->saved_raw_stdout = mi->raw_stdout;
+      mi->raw_stdout = out;
     }
   else
     {
-      raw_stdout = saved_raw_stdout;
-      saved_raw_stdout = NULL;
+      mi->raw_stdout = mi->saved_raw_stdout;
+      mi->saved_raw_stdout = NULL;
     }
   
-  mi_console_set_raw (mi->out, raw_stdout);
-  mi_console_set_raw (mi->err, raw_stdout);
-  mi_console_set_raw (mi->log, raw_stdout);
-  mi_console_set_raw (mi->targ, raw_stdout);
-  mi_console_set_raw (mi->event_channel, raw_stdout);
+  mi_console_set_raw (mi->out, mi->raw_stdout);
+  mi_console_set_raw (mi->err, mi->raw_stdout);
+  mi_console_set_raw (mi->log, mi->raw_stdout);
+  mi_console_set_raw (mi->targ, mi->raw_stdout);
+  mi_console_set_raw (mi->event_channel, mi->raw_stdout);
 
   return 1;
 }
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 7cb7bf5..a3b55a8746 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -72,8 +72,6 @@ enum
 
 int mi_debug_p;
 
-struct ui_file *raw_stdout;
-
 /* This is used to pass the current command timestamp down to
    continuation routines.  */
 static struct mi_timestamp *current_command_ts;
@@ -149,18 +147,21 @@ mi_async_p (void)
 
 static void timestamp (struct mi_timestamp *tv);
 
-static void print_diff_now (struct mi_timestamp *start);
-static void print_diff (struct mi_timestamp *start, struct mi_timestamp *end);
+static void print_diff (struct ui_file *file, struct mi_timestamp *start,
+			struct mi_timestamp *end);
 
 void
 mi_cmd_gdb_exit (char *command, char **argv, int argc)
 {
+  struct mi_interp *mi
+    = (struct mi_interp *) interp_data (current_interpreter ());
+
   /* We have to print everything right here because we never return.  */
   if (current_token)
-    fputs_unfiltered (current_token, raw_stdout);
-  fputs_unfiltered ("^exit\n", raw_stdout);
-  mi_out_put (current_uiout, raw_stdout);
-  gdb_flush (raw_stdout);
+    fputs_unfiltered (current_token, mi->raw_stdout);
+  fputs_unfiltered ("^exit\n", mi->raw_stdout);
+  mi_out_put (current_uiout, mi->raw_stdout);
+  gdb_flush (mi->raw_stdout);
   /* FIXME: The function called is not yet a formal libgdb function.  */
   quit_force (NULL, FROM_TTY);
 }
@@ -1981,6 +1982,7 @@ mi_cmd_remove_inferior (char *command, char **argv, int argc)
 static void
 captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context)
 {
+  struct mi_interp *mi = (struct mi_interp *) interp_data (command_interp ());
   struct cleanup *cleanup;
 
   if (do_timings)
@@ -1997,7 +1999,8 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context)
       /* A MI command was read from the input stream.  */
       if (mi_debug_p)
 	/* FIXME: gdb_???? */
-	fprintf_unfiltered (raw_stdout, " token=`%s' command=`%s' args=`%s'\n",
+	fprintf_unfiltered (mi->raw_stdout,
+			    " token=`%s' command=`%s' args=`%s'\n",
 			    context->token, context->command, context->args);
 
       mi_cmd_execute (context);
@@ -2010,15 +2013,15 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context)
 	 uiout will most likely crash in the mi_out_* routines.  */
       if (!running_result_record_printed)
 	{
-	  fputs_unfiltered (context->token, raw_stdout);
+	  fputs_unfiltered (context->token, mi->raw_stdout);
 	  /* There's no particularly good reason why target-connect results
 	     in not ^done.  Should kill ^connected for MI3.  */
 	  fputs_unfiltered (strcmp (context->command, "target-select") == 0
-			    ? "^connected" : "^done", raw_stdout);
-	  mi_out_put (uiout, raw_stdout);
+			    ? "^connected" : "^done", mi->raw_stdout);
+	  mi_out_put (uiout, mi->raw_stdout);
 	  mi_out_rewind (uiout);
-	  mi_print_timing_maybe ();
-	  fputs_unfiltered ("\n", raw_stdout);
+	  mi_print_timing_maybe (mi->raw_stdout);
+	  fputs_unfiltered ("\n", mi->raw_stdout);
 	}
       else
 	/* The command does not want anything to be printed.  In that
@@ -2049,12 +2052,12 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context)
 	  {
 	    if (!running_result_record_printed)
 	      {
-		fputs_unfiltered (context->token, raw_stdout);
-		fputs_unfiltered ("^done", raw_stdout);
-		mi_out_put (uiout, raw_stdout);
+		fputs_unfiltered (context->token, mi->raw_stdout);
+		fputs_unfiltered ("^done", mi->raw_stdout);
+		mi_out_put (uiout, mi->raw_stdout);
 		mi_out_rewind (uiout);
-		mi_print_timing_maybe ();
-		fputs_unfiltered ("\n", raw_stdout);
+		mi_print_timing_maybe (mi->raw_stdout);
+		fputs_unfiltered ("\n", mi->raw_stdout);
 	      }
 	    else
 	      mi_out_rewind (uiout);
@@ -2071,22 +2074,25 @@ captured_mi_execute_command (struct ui_out *uiout, struct mi_parse *context)
 static void
 mi_print_exception (const char *token, struct gdb_exception exception)
 {
-  fputs_unfiltered (token, raw_stdout);
-  fputs_unfiltered ("^error,msg=\"", raw_stdout);
+  struct mi_interp *mi
+    = (struct mi_interp *) interp_data (current_interpreter ());
+
+  fputs_unfiltered (token, mi->raw_stdout);
+  fputs_unfiltered ("^error,msg=\"", mi->raw_stdout);
   if (exception.message == NULL)
-    fputs_unfiltered ("unknown error", raw_stdout);
+    fputs_unfiltered ("unknown error", mi->raw_stdout);
   else
-    fputstr_unfiltered (exception.message, '"', raw_stdout);
-  fputs_unfiltered ("\"", raw_stdout);
+    fputstr_unfiltered (exception.message, '"', mi->raw_stdout);
+  fputs_unfiltered ("\"", mi->raw_stdout);
 
   switch (exception.error)
     {
       case UNDEFINED_COMMAND_ERROR:
-	fputs_unfiltered (",code=\"undefined-command\"", raw_stdout);
+	fputs_unfiltered (",code=\"undefined-command\"", mi->raw_stdout);
 	break;
     }
 
-  fputs_unfiltered ("\n", raw_stdout);
+  fputs_unfiltered ("\n", mi->raw_stdout);
 }
 
 void
@@ -2357,6 +2363,8 @@ mi_load_progress (const char *section_name,
   int new_section;
   struct ui_out *saved_uiout;
   struct ui_out *uiout;
+  struct mi_interp *mi
+    = (struct mi_interp *) interp_data (current_interpreter ());
 
   /* This function is called through deprecated_show_load_progress
      which means uiout may not be correct.  Fix it for the duration
@@ -2398,16 +2406,16 @@ mi_load_progress (const char *section_name,
       previous_sect_name = xstrdup (section_name);
 
       if (current_token)
-	fputs_unfiltered (current_token, raw_stdout);
-      fputs_unfiltered ("+download", raw_stdout);
+	fputs_unfiltered (current_token, mi->raw_stdout);
+      fputs_unfiltered ("+download", mi->raw_stdout);
       cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
       ui_out_field_string (uiout, "section", section_name);
       ui_out_field_int (uiout, "section-size", total_section);
       ui_out_field_int (uiout, "total-size", grand_total);
       do_cleanups (cleanup_tuple);
-      mi_out_put (uiout, raw_stdout);
-      fputs_unfiltered ("\n", raw_stdout);
-      gdb_flush (raw_stdout);
+      mi_out_put (uiout, mi->raw_stdout);
+      fputs_unfiltered ("\n", mi->raw_stdout);
+      gdb_flush (mi->raw_stdout);
     }
 
   if (delta.tv_sec >= update_threshold.tv_sec &&
@@ -2418,8 +2426,8 @@ mi_load_progress (const char *section_name,
       last_update.tv_sec = time_now.tv_sec;
       last_update.tv_usec = time_now.tv_usec;
       if (current_token)
-	fputs_unfiltered (current_token, raw_stdout);
-      fputs_unfiltered ("+download", raw_stdout);
+	fputs_unfiltered (current_token, mi->raw_stdout);
+      fputs_unfiltered ("+download", mi->raw_stdout);
       cleanup_tuple = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
       ui_out_field_string (uiout, "section", section_name);
       ui_out_field_int (uiout, "section-sent", sent_so_far);
@@ -2427,9 +2435,9 @@ mi_load_progress (const char *section_name,
       ui_out_field_int (uiout, "total-sent", total_sent);
       ui_out_field_int (uiout, "total-size", grand_total);
       do_cleanups (cleanup_tuple);
-      mi_out_put (uiout, raw_stdout);
-      fputs_unfiltered ("\n", raw_stdout);
-      gdb_flush (raw_stdout);
+      mi_out_put (uiout, mi->raw_stdout);
+      fputs_unfiltered ("\n", mi->raw_stdout);
+      gdb_flush (mi->raw_stdout);
     }
 
   xfree (uiout);
@@ -2459,21 +2467,21 @@ timestamp (struct mi_timestamp *tv)
 }
 
 static void
-print_diff_now (struct mi_timestamp *start)
+print_diff_now (struct ui_file *file, struct mi_timestamp *start)
 {
   struct mi_timestamp now;
 
   timestamp (&now);
-  print_diff (start, &now);
+  print_diff (file, start, &now);
 }
 
 void
-mi_print_timing_maybe (void)
+mi_print_timing_maybe (struct ui_file *file)
 {
   /* If the command is -enable-timing then do_timings may be true
      whilst current_command_ts is not initialized.  */
   if (do_timings && current_command_ts)
-    print_diff_now (current_command_ts);
+    print_diff_now (file, current_command_ts);
 }
 
 static long
@@ -2484,10 +2492,11 @@ timeval_diff (struct timeval start, struct timeval end)
 }
 
 static void
-print_diff (struct mi_timestamp *start, struct mi_timestamp *end)
+print_diff (struct ui_file *file, struct mi_timestamp *start,
+	    struct mi_timestamp *end)
 {
   fprintf_unfiltered
-    (raw_stdout,
+    (file,
      ",time={wallclock=\"%0.5f\",user=\"%0.5f\",system=\"%0.5f\"}",
      timeval_diff (start->wallclock, end->wallclock) / 1000000.0,
      timeval_diff (start->utime, end->utime) / 1000000.0,
diff --git a/gdb/mi/mi-main.h b/gdb/mi/mi-main.h
index b2face1..18000cf 100644
--- a/gdb/mi/mi-main.h
+++ b/gdb/mi/mi-main.h
@@ -20,13 +20,15 @@
 #ifndef MI_MAIN_H
 #define MI_MAIN_H
 
+struct ui_file;
+
 extern void mi_load_progress (const char *section_name,
 			      unsigned long sent_so_far,
 			      unsigned long total_section,
 			      unsigned long total_sent,
 			      unsigned long grand_total);
 
-extern void mi_print_timing_maybe (void);
+extern void mi_print_timing_maybe (struct ui_file *file);
 
 /* Whether MI is in async mode.  */
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 19/34] Simplify starting the command event loop
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (32 preceding siblings ...)
  2016-05-06 12:53 ` [PATCH v3 09/34] Make instream be per UI Pedro Alves
@ 2016-05-06 12:53 ` Pedro Alves
  2016-05-26 18:37 ` [PATCH v3 35/34] Add "new-ui console" tests Pedro Alves
  2016-06-21  0:23 ` [pushed] Re: [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:53 UTC (permalink / raw)
  To: gdb-patches

All interpreter types (CLI/TUI/MI) print the prompt, and then call
start_event_loop.

Because we'll need an interpreter hook to display the
interpreter-specific prompt before going back to the event loop,
without actually starting an event loop, this patch moves the
start_event_loop call to common code, and replaces the command_loop
hook with a pre_command_look hook, that now just prints the prompt.

Turns out to be a cleanup on its own right anyway.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-interp.c (cli_interpreter_pre_command_loop): New
	function.
	(cli_interp_procs): Install it instead of cli_command_loop.
	* cli/cli-interp.h (cli_interpreter_pre_command_loop): Declare.
	* event-top.c (cli_command_loop): Delete.
	* interps.c (interp_new): Remove reference to command_loop_proc.
	(current_interp_command_loop): Delete.
	(interp_pre_command_loop): New function.
	(interp_command_loop_ftype): Delete.
	* interps.h (interp_pre_command_loop_ftype): New typedef.
	(struct interp_procs) <command_loop_proc>: Delele field.
	<pre_command_loop_proc>: New field.
	(current_interp_command_loop): Delete declaration.
	(interp_pre_command_loop): New declaration.
	* main.c (captured_command_loop): Call interp_pre_command_loop
	instead of current_interp_command_loop and start an event loop.
	* mi/mi-interp.c (mi_command_loop): Delete.
	(mi_interpreter_pre_command_loop): New.
	(mi_interp_procs): Update.
	* tui/tui-interp.c (tui_interp_procs): Install
	cli_interpreter_pre_command_loop instead of cli_command_loop.
---
 gdb/cli/cli-interp.c | 10 +++++++++-
 gdb/cli/cli-interp.h |  2 ++
 gdb/event-top.c      | 13 -------------
 gdb/interps.c        | 16 ++++++----------
 gdb/interps.h        | 12 ++++++++----
 gdb/main.c           |  7 ++++++-
 gdb/mi/mi-interp.c   |  9 +++------
 gdb/tui/tui-interp.c |  2 +-
 8 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index d67baf3..599507b 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -190,6 +190,14 @@ cli_on_command_error (void)
   display_gdb_prompt (NULL);
 }
 
+/* pre_command_loop implementation.  */
+
+void
+cli_interpreter_pre_command_loop (struct interp *self)
+{
+  display_gdb_prompt (0);
+}
+
 /* These implement the cli out interpreter: */
 
 static void *
@@ -312,7 +320,7 @@ static const struct interp_procs cli_interp_procs = {
   cli_interpreter_exec,		/* exec_proc */
   cli_ui_out,			/* ui_out_proc */
   NULL,                       	/* set_logging_proc */
-  cli_command_loop,		/* command_loop_proc */
+  cli_interpreter_pre_command_loop, /* pre_command_loop_proc */
   cli_interpreter_supports_command_editing, /* supports_command_editing_proc */
 };
 
diff --git a/gdb/cli/cli-interp.h b/gdb/cli/cli-interp.h
index 07b7505..85be118 100644
--- a/gdb/cli/cli-interp.h
+++ b/gdb/cli/cli-interp.h
@@ -22,4 +22,6 @@ struct interp;
 
 extern int cli_interpreter_supports_command_editing (struct interp *interp);
 
+extern void cli_interpreter_pre_command_loop (struct interp *self);
+
 #endif
diff --git a/gdb/event-top.c b/gdb/event-top.c
index e90d00d..5e42c56 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -216,19 +216,6 @@ gdb_rl_callback_handler (char *rl)
     throw_exception_sjlj (gdb_rl_expt);
 }
 
-/* Initialize all the necessary variables, start the event loop,
-   register readline, and stdin, start the loop.  The DATA is the
-   interpreter data cookie, ignored for now.  */
-
-void
-cli_command_loop (void *data)
-{
-  display_gdb_prompt (0);
-
-  /* Now it's time to start the event loop.  */
-  start_event_loop ();
-}
-
 /* Change the function to be invoked every time there is a character
    ready on stdin.  This is used when the user sets the editing off,
    therefore bypassing readline, and letting gdb handle the input
diff --git a/gdb/interps.c b/gdb/interps.c
index 36e0422..acc6c1d 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -109,9 +109,6 @@ interp_new (const char *name, const struct interp_procs *procs, void *data)
   new_interp->procs = procs;
   new_interp->inited = 0;
 
-  /* Check for required procs.  */
-  gdb_assert (procs->command_loop_proc != NULL);
-
   return new_interp;
 }
 
@@ -404,16 +401,15 @@ command_interp (void)
     return ui_interp->current_interpreter;
 }
 
-/* Run the current command interpreter's main loop.  */
+/* See interps.h.  */
+
 void
-current_interp_command_loop (void)
+interp_pre_command_loop (struct interp *interp)
 {
-  struct ui_interp_info *ui_interp = get_current_interp_info ();
-  struct interp *interp = ui_interp->current_interpreter;
-
-  gdb_assert (ui_interp->current_interpreter != NULL);
+  gdb_assert (interp != NULL);
 
-  interp->procs->command_loop_proc (interp->data);
+  if (interp->procs->pre_command_loop_proc != NULL)
+    interp->procs->pre_command_loop_proc (interp);
 }
 
 /* See interp.h  */
diff --git a/gdb/interps.h b/gdb/interps.h
index 45f9bf2..af97c6a 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -47,7 +47,7 @@ typedef int (interp_resume_ftype) (void *data);
 typedef int (interp_suspend_ftype) (void *data);
 typedef struct gdb_exception (interp_exec_ftype) (void *data,
 						  const char *command);
-typedef void (interp_command_loop_ftype) (void *data);
+typedef void (interp_pre_command_loop_ftype) (struct interp *self);
 typedef struct ui_out *(interp_ui_out_ftype) (struct interp *self);
 
 typedef int (interp_set_logging_ftype) (struct interp *self, int start_log,
@@ -74,7 +74,9 @@ struct interp_procs
      disabled.  */
   interp_set_logging_ftype *set_logging_proc;
 
-  interp_command_loop_ftype *command_loop_proc;
+  /* Called before starting an event loop, to give the interpreter a
+     chance to e.g., print a prompt.  */
+  interp_pre_command_loop_ftype *pre_command_loop_proc;
 
   /* Returns true if this interpreter supports using the readline
      library; false if it uses GDB's own simplified readline
@@ -101,8 +103,6 @@ extern struct interp *interp_set_temp (const char *name);
 
 extern int current_interp_named_p (const char *name);
 
-extern void current_interp_command_loop (void);
-
 /* Call this function to give the current interpreter an opportunity
    to do any special handling of streams when logging is enabled or
    disabled.  START_LOG is 1 when logging is starting, 0 when it ends,
@@ -128,6 +128,10 @@ extern void clear_interpreter_hooks (void);
    if it uses GDB's own simplified form of readline.  */
 extern int interp_supports_command_editing (struct interp *interp);
 
+/* Called before starting an event loop, to give the interpreter a
+   chance to e.g., print a prompt.  */
+extern void interp_pre_command_loop (struct interp *interp);
+
 /* well-known interpreters */
 #define INTERP_CONSOLE		"console"
 #define INTERP_MI1             "mi1"
diff --git a/gdb/main.c b/gdb/main.c
index 58e510e..0bf52a9 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -315,7 +315,12 @@ captured_command_loop (void *data)
      here on.  */
   current_ui->async = 1;
 
-  current_interp_command_loop ();
+  /* Give the interpreter a chance to print a prompt.  */
+  interp_pre_command_loop (top_level_interpreter ());
+
+  /* Now it's time to start the event loop.  */
+  start_event_loop ();
+
   /* FIXME: cagney/1999-11-05: A correct command_loop() implementaton
      would clean things up (restoring the cleanup chain) to the state
      they were just prior to the call.  Technically, this means that
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index d4c89f7..240ab8d 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -44,7 +44,6 @@
 
 static void mi_execute_command_wrapper (const char *cmd);
 static void mi_execute_command_input_handler (char *cmd);
-static void mi_command_loop (void *data);
 
 /* These are hooks that we put in place while doing interpreter_exec
    so we can report interesting things that happened "behind the MI's
@@ -328,9 +327,9 @@ mi_execute_command_input_handler (char *cmd)
 }
 
 static void
-mi_command_loop (void *data)
+mi_interpreter_pre_command_loop (struct interp *self)
 {
-  struct mi_interp *mi = (struct mi_interp *) data;
+  struct mi_interp *mi = (struct mi_interp *) interp_data (self);
 
   /* Turn off 8 bit strings in quoted output.  Any character with the
      high bit set is printed using C's octal format.  */
@@ -338,8 +337,6 @@ mi_command_loop (void *data)
 
   /* Tell the world that we're alive.  */
   display_mi_prompt (mi);
-
-  start_event_loop ();
 }
 
 static void
@@ -1418,7 +1415,7 @@ static const struct interp_procs mi_interp_procs =
   mi_interpreter_exec,		/* exec_proc */
   mi_ui_out, 			/* ui_out_proc */
   mi_set_logging,		/* set_logging_proc */
-  mi_command_loop		/* command_loop_proc */
+  mi_interpreter_pre_command_loop /* pre_command_loop_proc */
 };
 
 /* Factory for MI interpreters.  */
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index fc3c0ff..950345c 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -278,7 +278,7 @@ static const struct interp_procs tui_interp_procs = {
   tui_exec,
   tui_ui_out,
   NULL,
-  cli_command_loop,
+  cli_interpreter_pre_command_loop,
   cli_interpreter_supports_command_editing,
 };
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 09/34] Make instream be per UI
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (31 preceding siblings ...)
  2016-05-06 12:52 ` [PATCH v3 18/34] Make raw_stdout be per MI instance Pedro Alves
@ 2016-05-06 12:53 ` Pedro Alves
  2016-05-06 12:53 ` [PATCH v3 19/34] Simplify starting the command event loop Pedro Alves
                   ` (2 subsequent siblings)
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-06 12:53 UTC (permalink / raw)
  To: gdb-patches

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-script.c (execute_user_command, read_next_line)
	(read_next_line): Adjust to per-UI instream.
	* event-top.c (stdin_event_handler, command_handler)
	(handle_line_of_input, command_line_handler)
	(gdb_readline_no_editing_callback, async_sigterm_handler)
	(gdb_setup_readline): Likewise.
	* inflow.c: Include top.h.
	(gdb_has_a_terminal, child_terminal_init_with_pgrp)
	(gdb_save_tty_state, child_terminal_inferior)
	(child_terminal_ours_1, copy_terminal_info): Use the main UI.
	(initialize_stdin_serial): Adjust to per-UI instream.
	* main.c (captured_command_loop, captured_main): Adjust to per-UI
	instream.
	* mi/mi-interp.c (mi_execute_command_wrapper): Likewise.
	* python/python.c (python_interactive_command): Likewise.
	* terminal.h (struct ui): Forward declare.
	(initialize_stdin_serial): Add struct ui parameter.
	* top.c (instream): Delete.
	(do_restore_instream_cleanup, read_command_file, dont_repeat)
	(gdb_readline_no_editing, command_line_input)
	(input_from_terminal_p, gdb_init): Adjust to per-UI instream.
	* top.h (struct ui) <instream>: New field.
	(instream): Delete declaration.
	(quit): Adjust to per-UI instream.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.gdb/selftest.exp (do_steps_and_nexts): Add new regexp.
---
 gdb/cli/cli-script.c               | 11 +++++++----
 gdb/event-top.c                    | 34 +++++++++++++++++++---------------
 gdb/main.c                         |  7 +++++--
 gdb/mi/mi-interp.c                 |  4 +++-
 gdb/python/python.c                |  3 ++-
 gdb/testsuite/gdb.gdb/selftest.exp |  4 ++++
 gdb/top.c                          | 36 +++++++++++++++++++-----------------
 gdb/top.h                          |  7 ++++++-
 gdb/utils.c                        |  4 +++-
 9 files changed, 68 insertions(+), 42 deletions(-)

diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 5fc01b3..0507c55 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -352,6 +352,7 @@ do_restore_user_call_depth (void * call_depth)
 void
 execute_user_command (struct cmd_list_element *c, char *args)
 {
+  struct ui *ui = current_ui;
   struct command_line *cmdlines;
   struct cleanup *old_chain;
   enum command_control_type ret;
@@ -372,8 +373,8 @@ execute_user_command (struct cmd_list_element *c, char *args)
 
   /* Set the instream to 0, indicating execution of a
      user-defined function.  */
-  make_cleanup (do_restore_instream_cleanup, instream);
-  instream = (FILE *) 0;
+  make_cleanup (do_restore_instream_cleanup, ui->instream);
+  ui->instream = NULL;
 
   /* Also set the global in_user_command, so that NULL instream is
      not confused with Insight.  */
@@ -931,6 +932,7 @@ realloc_body_list (struct command_line *command, int new_length)
 static char *
 read_next_line (void)
 {
+  struct ui *ui = current_ui;
   char *prompt_ptr, control_prompt[256];
   int i = 0;
 
@@ -938,7 +940,8 @@ read_next_line (void)
     error (_("Control nesting too deep!"));
 
   /* Set a prompt based on the nesting of the control commands.  */
-  if (instream == stdin || (instream == 0 && deprecated_readline_hook != NULL))
+  if (ui->instream == stdin
+      || (ui->instream == 0 && deprecated_readline_hook != NULL))
     {
       for (i = 0; i < control_level; i++)
 	control_prompt[i] = ' ';
@@ -949,7 +952,7 @@ read_next_line (void)
   else
     prompt_ptr = NULL;
 
-  return command_line_input (prompt_ptr, instream == stdin, "commands");
+  return command_line_input (prompt_ptr, ui->instream == stdin, "commands");
 }
 
 /* Process one input line.  If the command is an "end", return such an
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 63f6896..3e2f778 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -510,7 +510,7 @@ stdin_event_handler (int error, gdb_client_data client_data)
       printf_unfiltered (_("error detected on stdin\n"));
       delete_file_handler (input_fd);
       /* If stdin died, we may as well kill gdb.  */
-      quit_command ((char *) 0, stdin == instream);
+      quit_command ((char *) 0, stdin == ui->instream);
     }
   else
     {
@@ -566,10 +566,11 @@ async_disable_stdin (void)
 void
 command_handler (char *command)
 {
+  struct ui *ui = current_ui;
   struct cleanup *stat_chain;
   char *c;
 
-  if (instream == stdin)
+  if (ui->instream == stdin)
     reinitialize_more_filter ();
 
   stat_chain = make_command_stats_cleanup (1);
@@ -579,7 +580,7 @@ command_handler (char *command)
     ;
   if (c[0] != '#')
     {
-      execute_command (command, instream == stdin);
+      execute_command (command, ui->instream == stdin);
 
       /* Do any commands attached to breakpoint we stopped at.  */
       bpstat_do_actions ();
@@ -646,6 +647,7 @@ char *
 handle_line_of_input (struct buffer *cmd_line_buffer,
 		      char *rl, int repeat, char *annotation_suffix)
 {
+  struct ui *ui = current_ui;
   char *p1;
   char *cmd;
 
@@ -660,7 +662,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
      command, but leave ownership of memory to the buffer .  */
   cmd_line_buffer->used_size = 0;
 
-  if (annotation_level > 1 && instream == stdin)
+  if (annotation_level > 1 && ui->instream == stdin)
     {
       printf_unfiltered (("\n\032\032post-"));
       puts_unfiltered (annotation_suffix);
@@ -677,8 +679,8 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
     }
 
   /* Do history expansion if that is wished.  */
-  if (history_expansion_p && instream == stdin
-      && ISATTY (instream))
+  if (history_expansion_p && ui->instream == stdin
+      && ISATTY (ui->instream))
     {
       char *history_value;
       int expanded;
@@ -748,9 +750,11 @@ void
 command_line_handler (char *rl)
 {
   struct buffer *line_buffer = get_command_line_buffer ();
+  struct ui *ui = current_ui;
   char *cmd;
 
-  cmd = handle_line_of_input (line_buffer, rl, instream == stdin, "prompt");
+  cmd = handle_line_of_input (line_buffer, rl, ui->instream == stdin,
+			      "prompt");
   if (cmd == (char *) EOF)
     {
       /* stdin closed.  The connection with the terminal is gone.
@@ -758,7 +762,7 @@ command_line_handler (char *rl)
 	 hung up but GDB is still alive.  In such a case, we just quit
 	 gdb killing the inferior program too.  */
       printf_unfiltered ("quit\n");
-      execute_command ("quit", stdin == instream);
+      execute_command ("quit", stdin == ui->instream);
     }
   else if (cmd == NULL)
     {
@@ -793,9 +797,9 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
      stream after '\n'.  If we buffer the input and fgetc drains the
      stream, getting stuff beyond the newline as well, a select, done
      afterwards will not trigger.  */
-  if (!done_once && !ISATTY (instream))
+  if (!done_once && !ISATTY (ui->instream))
     {
-      setbuf (instream, NULL);
+      setbuf (ui->instream, NULL);
       done_once = 1;
     }
 
@@ -811,7 +815,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
     {
       /* Read from stdin if we are executing a user defined command.
          This is the right thing for prompt_for_continue, at least.  */
-      c = fgetc (instream ? instream : stdin);
+      c = fgetc (ui->instream ? ui->instream : stdin);
 
       if (c == EOF)
 	{
@@ -1059,7 +1063,7 @@ interruptible_select (int n,
 static void
 async_sigterm_handler (gdb_client_data arg)
 {
-  quit_force (NULL, stdin == instream);
+  quit_force (NULL, stdin == current_ui->instream);
 }
 
 /* See defs.h.  */
@@ -1241,7 +1245,7 @@ gdb_setup_readline (void)
 
   /* If the input stream is connected to a terminal, turn on
      editing.  */
-  if (ISATTY (instream))
+  if (ISATTY (ui->instream))
     {
       /* Tell gdb that we will be using the readline library.  This
 	 could be overwritten by a command in .gdbinit like 'set
@@ -1264,11 +1268,11 @@ gdb_setup_readline (void)
   ui->input_handler = command_line_handler;
 
   /* Tell readline to use the same input stream that gdb uses.  */
-  rl_instream = instream;
+  rl_instream = ui->instream;
 
   /* Get a file descriptor for the input stream, so that we can
      register it with the event loop.  */
-  input_fd = fileno (instream);
+  input_fd = fileno (ui->instream);
 
   /* Now we need to create the event sources for the input file
      descriptor.  */
diff --git a/gdb/main.c b/gdb/main.c
index d84340e..7d7b52a 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -309,6 +309,8 @@ setup_alternate_signal_stack (void)
 static int
 captured_command_loop (void *data)
 {
+  struct ui *ui = current_ui;
+
   /* Top-level execution commands can be run in the background from
      here on.  */
   current_ui->async = 1;
@@ -326,7 +328,7 @@ captured_command_loop (void *data)
      error) we try to quit.  If the quit is aborted, catch_errors()
      which called this catch the signal and restart the command
      loop.  */
-  quit_command (NULL, instream == stdin);
+  quit_command (NULL, ui->instream == stdin);
   return 1;
 }
 
@@ -435,6 +437,7 @@ DEF_VEC_O (cmdarg_s);
 static int
 captured_main (void *data)
 {
+  struct ui *ui = current_ui;
   struct captured_main_args *context = (struct captured_main_args *) data;
   int argc = context->argc;
   char **argv = context->argv;
@@ -504,7 +507,7 @@ captured_main (void *data)
   ndir = 0;
 
   saved_command_line = (char *) xstrdup ("");
-  instream = stdin;
+  ui->instream = stdin;
 
 #ifdef __MINGW32__
   /* Ensure stderr is unbuffered.  A Cygwin pty or pipe is implemented
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index f9820cb..22250d9 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -283,7 +283,9 @@ mi_interp_query_hook (const char *ctlstr, va_list ap)
 static void
 mi_execute_command_wrapper (const char *cmd)
 {
-  mi_execute_command (cmd, stdin == instream);
+  struct ui *ui = current_ui;
+
+  mi_execute_command (cmd, stdin == ui->instream);
 }
 
 /* Observer for the synchronous_command_done notification.  */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index fa1c78e..06fd468 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -318,6 +318,7 @@ eval_python_command (const char *command)
 static void
 python_interactive_command (char *arg, int from_tty)
 {
+  struct ui *ui = current_ui;
   struct cleanup *cleanup;
   int err;
 
@@ -341,7 +342,7 @@ python_interactive_command (char *arg, int from_tty)
     }
   else
     {
-      err = PyRun_InteractiveLoop (instream, "<stdin>");
+      err = PyRun_InteractiveLoop (ui->instream, "<stdin>");
       dont_repeat ();
     }
 
diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp
index 969797a..af0026c 100644
--- a/gdb/testsuite/gdb.gdb/selftest.exp
+++ b/gdb/testsuite/gdb.gdb/selftest.exp
@@ -205,6 +205,10 @@ proc do_steps_and_nexts {} {
 		set description "step over gdb_stderr initialization"
 		set command "step"
 	    }
+	    -re "ui = current_ui.*$gdb_prompt $" {
+		set description "step over top_level initialization"
+		set command "step"
+	    }
 	    -re ".*main.c.*No such file or directory.*$gdb_prompt $" {
 		setup_xfail "rs6000-*-aix3*"
 		fail "must be able to list source lines"
diff --git a/gdb/top.c b/gdb/top.c
index 3842f0c..733580f 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -123,13 +123,6 @@ show_confirm (struct ui_file *file, int from_tty,
 		    value);
 }
 
-/* stdio stream that command input is being read from.  Set to stdin
-   normally.  Set by source_command to the file we are sourcing.  Set
-   to NULL if we are executing a user-defined command or interacting
-   via a GUI.  */
-
-FILE *instream;
-
 /* Flag to indicate whether a user defined command is currently running.  */
 
 int in_user_command;
@@ -286,23 +279,26 @@ quit_cover (void)
 void
 do_restore_instream_cleanup (void *stream)
 {
+  struct ui *ui = current_ui;
+
   /* Restore the previous input stream.  */
-  instream = (FILE *) stream;
+  ui->instream = (FILE *) stream;
 }
 
 /* Read commands from STREAM.  */
 void
 read_command_file (FILE *stream)
 {
+  struct ui *ui = current_ui;
   struct cleanup *cleanups;
 
-  cleanups = make_cleanup (do_restore_instream_cleanup, instream);
-  instream = stream;
+  cleanups = make_cleanup (do_restore_instream_cleanup, ui->instream);
+  ui->instream = stream;
 
   /* Read commands from `instream' and execute them until end of file
      or error reading instream.  */
 
-  while (instream != NULL && !feof (instream))
+  while (ui->instream != NULL && !feof (ui->instream))
     {
       char *command;
 
@@ -568,13 +564,15 @@ static int suppress_dont_repeat = 0;
 void
 dont_repeat (void)
 {
+  struct ui *ui = current_ui;
+
   if (suppress_dont_repeat || server_command)
     return;
 
   /* If we aren't reading from standard input, we are saving the last
      thing read from stdin in line and don't want to delete it.  Null
      lines won't repeat here in any case.  */
-  if (instream == stdin)
+  if (ui->instream == stdin)
     *saved_command_line = 0;
 }
 
@@ -603,9 +601,10 @@ static char *
 gdb_readline_no_editing (const char *prompt)
 {
   struct buffer line_buffer;
+  struct ui *ui = current_ui;
   /* Read from stdin if we are executing a user defined command.  This
      is the right thing for prompt_for_continue, at least.  */
-  FILE *stream = instream != NULL ? instream : stdin;
+  FILE *stream = ui->instream != NULL ? ui->instream : stdin;
   int fd = fileno (stream);
 
   buffer_init (&line_buffer);
@@ -1047,6 +1046,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 {
   static struct buffer cmd_line_buffer;
   static int cmd_line_buffer_initialized;
+  struct ui *ui = current_ui;
   const char *prompt = prompt_arg;
   char *cmd;
 
@@ -1054,7 +1054,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
   if (annotation_suffix == NULL)
     annotation_suffix = "";
 
-  if (annotation_level > 1 && instream == stdin)
+  if (annotation_level > 1 && ui->instream == stdin)
     {
       char *local_prompt;
 
@@ -1100,7 +1100,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
       if (source_file_name != NULL)
 	++source_line_number;
 
-      if (annotation_level > 1 && instream == stdin)
+      if (annotation_level > 1 && ui->instream == stdin)
 	{
 	  puts_unfiltered ("\n\032\032pre-");
 	  puts_unfiltered (annotation_suffix);
@@ -1511,16 +1511,18 @@ quit_force (char *args, int from_tty)
 int
 input_from_terminal_p (void)
 {
+  struct ui *ui = current_ui;
+
   if (batch_flag)
     return 0;
 
-  if (gdb_has_a_terminal () && instream == stdin)
+  if (gdb_has_a_terminal () && ui->instream == stdin)
     return 1;
 
   /* If INSTREAM is unset, and we are not in a user command, we
      must be in Insight.  That's like having a terminal, for our
      purposes.  */
-  if (instream == NULL && !in_user_command)
+  if (ui->instream == NULL && !in_user_command)
     return 1;
 
   return 0;
diff --git a/gdb/top.h b/gdb/top.h
index 8f01f78..bb84097 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -68,6 +68,12 @@ struct ui
      "start" -ex "next"') are processed.  */
   int async;
 
+  /* stdio stream that command input is being read from.  Set to stdin
+     normally.  Set by source_command to the file we are sourcing.
+     Set to NULL if we are executing a user-defined command or
+     interacting via a GUI.  */
+  FILE *instream;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
@@ -121,7 +127,6 @@ extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
 
 /* From top.c.  */
 extern char *saved_command_line;
-extern FILE *instream;
 extern int in_user_command;
 extern int confirm;
 extern char gdb_dirbuf[1024];
diff --git a/gdb/utils.c b/gdb/utils.c
index db5104d..78d2e98 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1047,10 +1047,12 @@ print_sys_errmsg (const char *string, int errcode)
 void
 quit (void)
 {
+  struct ui *ui = current_ui;
+
   if (sync_quit_force_run)
     {
       sync_quit_force_run = 0;
-      quit_force (NULL, stdin == instream);
+      quit_force (NULL, stdin == ui->instream);
     }
 
 #ifdef __MSDOS__
-- 
2.5.5

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels
  2016-05-06 12:42 ` [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels Pedro Alves
@ 2016-05-06 13:04   ` Eli Zaretskii
  2016-05-26 11:11     ` Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Eli Zaretskii @ 2016-05-06 13:04 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> From: Pedro Alves <palves@redhat.com>
> Date: Fri,  6 May 2016 13:35:00 +0100
> 
> +Although you may only choose a single interpreter at startup, it is
> +possible to run an independent interpreter on a separate channel.

"Channel"?  What's that?  Can we find a better word?

No other comments to the doc part.  Thanks.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 05/34] Make the interpreters be per UI
  2016-05-06 12:43 ` [PATCH v3 05/34] Make the interpreters " Pedro Alves
@ 2016-05-18 17:51   ` Simon Marchi
  2016-05-26 18:08     ` Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-05-18 17:51 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-06 08:34 AM, Pedro Alves wrote:
> Make each UI have its own interpreter list, top level interpreter,
> current interpreter, etc.  The "interpreter_async" global is not
> really specific to an struct interp (it crosses interpreter-exec ...),
> so I moved it to "struct ui" directly, while the other globals were
> left hidden in interps.c, opaque to the rest of GDB.
> 
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* breakpoint.c (bpstat_do_actions_1): Access the current UI's
> 	async field instead of the interpreter_async global.
> 	* cli/cli-script.c (execute_user_command, while_command)
> 	(if_command, script_from_file): Likewise.
> 	* compile/compile.c: Include top.h instead of interps.h.
> 	(compile_file_command, compile_code_command)
> 	(compile_print_command): Access the current UI's async field
> 	instead of the interpreter_async global.
> 	* guile/guile.c: Include top.h instead of interps.h.
> 	(guile_repl_command, guile_command, gdbscm_execute_gdb_command):
> 	Access the current UI's async field instead of the
> 	interpreter_async global.
> 	* guile/scm-ports.c: Include top.h instead of interps.h.
> 	(ioscm_with_output_to_port_worker): Access the current UI's async
> 	field instead of the interpreter_async global.
> 	* inf-loop.c (inferior_event_handler): Likewise.
> 	* infcall.c (run_inferior_call): Likewise.
> 	* infrun.c (reinstall_readline_callback_handler_cleanup)
> 	(fetch_inferior_event): Likewise.
> 	* interps.c (interpreter_async): Delete.
> 	(struct ui_interp_info): New.
> 	(get_current_interp_info): New function.
> 	(interp_list, current_interpreter, top_level_interpreter_ptr):
> 	Delete.
> 	(interp_add, interp_set, interp_lookup, interp_ui_out)
> 	(current_interp_set_logging, interp_set_temp)
> 	(current_interp_named_p): Adjust to per-UI interpreters.
> 	(command_interpreter): Delete.
> 	(command_interp, current_interp_command_loop, interp_quiet_p)
> 	(interp_exec, interpreter_exec_cmd, interpreter_completer)
> 	(top_level_interpretertop_level_interpreter)

Two pastes here.

> diff --git a/gdb/interps.c b/gdb/interps.c
> index b188d08..7f57132 100644
> --- a/gdb/interps.c
> +++ b/gdb/interps.c
> @@ -39,11 +39,31 @@
>  #include "top.h"		/* For command_loop.  */
>  #include "continuations.h"
>  
> -/* True if the current interpreter in is async mode.  See interps.h
> -   for more details.  This starts out disabled, until all the explicit
> -   command line arguments (e.g., `gdb -ex "start" -ex "next"') are
> -   processed.  */
> -int interpreter_async = 0;
> +/* Each UI has its own independent set of interpreters.  */
> +
> +struct ui_interp_info
> +{
> +  /* Each top level has its own independent set of interpreters.  */
> +  struct interp *interp_list;
> +  struct interp *current_interpreter;
> +  struct interp *top_level_interpreter_ptr;

Could this be renamed top_level_interpreter?  I guess it was named _ptr to avoid clash in the global namespace.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 06/34] Introduce interpreter factories
  2016-05-06 12:41 ` [PATCH v3 06/34] Introduce interpreter factories Pedro Alves
@ 2016-05-18 19:18   ` Simon Marchi
  2016-05-26 18:11     ` Pedro Alves
  2016-05-18 19:20   ` Simon Marchi
  1 sibling, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-05-18 19:18 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-06 08:34 AM, Pedro Alves wrote:
> +/* See interps.h.  */
> +
> +struct interp *
> +interp_lookup (const char *name)
> +{
> +  struct ui *ui = current_ui;
> +  struct interp_factory *factory;
> +  struct interp *interp;
> +  int ix;
> +
> +  if (name == NULL || strlen (name) == 0)
> +    return NULL;
> +
> +  /* Only create each interpreter once per top level.  */
> +  interp = interp_lookup_existing (name);
> +  if (interp != NULL)
> +    return interp;
> +
> +  for (ix = 0;
> +       VEC_iterate (interp_factory_p, interpreter_factories, ix, factory);
> +       ++ix)
> +    if (strcmp (factory->name, name) == 0)
> +      {
> +	interp = factory->func (name, ui);
> +	interp_add (interp);
> +	return interp;
> +      }
> +
> +  return NULL;
> +}
> +

I think there are some opportunities to reduce the number of functions that directly
access global state.  For example, I think it would be clearer if interp_lookup took
a struct ui* as argument instead of accessing current_ui.  It would show that it's used
to lookup an interpreter by name in a ui.  Similarly, it calls interp_lookup_existing and
interp_add, which both use get_current_interp_info(), which is essentially accessing
current_ui.  I believe it would be easier to follow if some caller provided the struct ui
and it was passed down by parameters.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 06/34] Introduce interpreter factories
  2016-05-06 12:41 ` [PATCH v3 06/34] Introduce interpreter factories Pedro Alves
  2016-05-18 19:18   ` Simon Marchi
@ 2016-05-18 19:20   ` Simon Marchi
  2016-05-26 18:08     ` Pedro Alves
  1 sibling, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-05-18 19:20 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-06 08:34 AM, Pedro Alves wrote:
> If every UI instance has its own set of interpreters, then the current
> scheme of creating the interpreters at GDB initialization time no
> longer works.  We need to create them whenever a new UI instance is
> created.
> 
> The scheme implemented here has each interpreter register an factory
> callback that when called creates a new instance of a specific type.
> Then, when some code in gdb looks up an interpreter (always by name),
> if there's none yet, the factory method is called to construct one.
> 
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* cli/cli-interp.c (cli_uiout): Delete, moved into ...
> 	(struct cli_interp): ... this new structure.
> 	(cli_on_normal_stop, cli_on_signal_received)
> 	(cli_on_end_stepping_range, cli_on_signal_exited, cli_on_exited)
> 	(cli_on_no_history): Use interp_ui_out.
> 	(cli_interpreter_init): If top level, set the cli_interp global.
> 	(cli_interpreter_init): Return the interp's data instead of NULL.
> 	(cli_interpreter_resume, cli_interpreter_exec, cli_ui_out): Adjust
> 	to cli_uiout being in the interpreter's data.
> 	(cli_interp_procs): New, factored out from _initialize_cli_interp.
> 	(cli_interp_factory): New function.
> 	(_initialize_cli_interp): Call interp_factory_register.
> 	* interps.c (interp_new): Add parameter 'data'.  Store it.
> 	(struct interp_factory): New function.
> 	(interp_factory_p): New typedef.  Define a VEC_P.
> 	(interpreter_factories): New global.
> 	(interp_factory_register): New function.
> 	(interp_add): Use interp_lookup_existing.
> 	(interp_lookup): Rename to ...
> 	(interp_lookup_existing): ... this.  Don't check for NULL or empty
> 	name here.
> 	(interp_lookup): Reimplement.
> 	(interpreter_completer): Complete on registered interpreter
> 	factories instead of interpreters.
> 	* interps.h (interp_factory_func): New typedef.
> 	(interp_factory_register): Declare.
> 	(interp_new): Adjust.
> 	(interp_lookup): Declare.
> 	* mi/mi-interp.c (mi_interp_procs): New, factored out from
> 	_initialize_mi_interp.
> 	(mi_interp_factory): New function.
> 	* tui/tui-interp.c (tui_init): If top level, set the tui_interp
> 	global.
> 	(tui_interp_procs): New.
> 	(tui_interp_factory): New function.
> 	(_initialize_tui_interp): Call interp_factory_register.
> ---
>  gdb/cli/cli-interp.c |  87 ++++++++++++++++++++++++++----------------
>  gdb/interps.c        | 105 +++++++++++++++++++++++++++++++++++++++++++--------
>  gdb/interps.h        |  21 ++++++++++-
>  gdb/mi/mi-interp.c   |  40 ++++++++++++--------
>  gdb/tui/tui-interp.c |  38 ++++++++++++-------
>  5 files changed, 214 insertions(+), 77 deletions(-)
> 
> diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
> index dfbd808..ac12a4c 100644
> --- a/gdb/cli/cli-interp.c
> +++ b/gdb/cli/cli-interp.c
> @@ -26,9 +26,14 @@
>  #include "infrun.h"
>  #include "observer.h"
>  
> -/* These are the ui_out and the interpreter for the console
> -   interpreter.  */
> -struct ui_out *cli_uiout;
> +/* The console interpreter.  */
> +struct cli_interp
> +{
> +  /* The ui_out for the console interpreter.  */
> +  struct ui_out *cli_uiout;
> +};
> +
> +/* The interpreter for the console interpreter.  */
>  static struct interp *cli_interp;
>  
>  /* Longjmp-safe wrapper for "execute_command".  */
> @@ -48,7 +53,7 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame)
>    if (!interp_quiet_p (cli_interp))
>      {
>        if (print_frame)
> -	print_stop_event (cli_uiout);
> +	print_stop_event (interp_ui_out (cli_interp));
>      }
>  }
>  
> @@ -58,7 +63,7 @@ static void
>  cli_on_signal_received (enum gdb_signal siggnal)
>  {
>    if (!interp_quiet_p (cli_interp))
> -    print_signal_received_reason (cli_uiout, siggnal);
> +    print_signal_received_reason (interp_ui_out (cli_interp), siggnal);
>  }
>  
>  /* Observer for the end_stepping_range notification.  */
> @@ -67,7 +72,7 @@ static void
>  cli_on_end_stepping_range (void)
>  {
>    if (!interp_quiet_p (cli_interp))
> -    print_end_stepping_range_reason (cli_uiout);
> +    print_end_stepping_range_reason (interp_ui_out (cli_interp));
>  }
>  
>  /* Observer for the signalled notification.  */
> @@ -76,7 +81,7 @@ static void
>  cli_on_signal_exited (enum gdb_signal siggnal)
>  {
>    if (!interp_quiet_p (cli_interp))
> -    print_signal_exited_reason (cli_uiout, siggnal);
> +    print_signal_exited_reason (interp_ui_out (cli_interp), siggnal);
>  }
>  
>  /* Observer for the exited notification.  */
> @@ -85,7 +90,7 @@ static void
>  cli_on_exited (int exitstatus)
>  {
>    if (!interp_quiet_p (cli_interp))
> -    print_exited_reason (cli_uiout, exitstatus);
> +    print_exited_reason (interp_ui_out (cli_interp), exitstatus);
>  }
>  
>  /* Observer for the no_history notification.  */
> @@ -94,7 +99,7 @@ static void
>  cli_on_no_history (void)
>  {
>    if (!interp_quiet_p (cli_interp))
> -    print_no_history_reason (cli_uiout);
> +    print_no_history_reason (interp_ui_out (cli_interp));
>  }
>  
>  /* Observer for the sync_execution_done notification.  */
> @@ -120,6 +125,9 @@ cli_on_command_error (void)
>  static void *
>  cli_interpreter_init (struct interp *self, int top_level)
>  {
> +  if (top_level)
> +    cli_interp = self;
> +
>    /* If changing this, remember to update tui-interp.c as well.  */
>    observer_attach_normal_stop (cli_on_normal_stop);
>    observer_attach_end_stepping_range (cli_on_end_stepping_range);
> @@ -130,12 +138,13 @@ cli_interpreter_init (struct interp *self, int top_level)
>    observer_attach_sync_execution_done (cli_on_sync_execution_done);
>    observer_attach_command_error (cli_on_command_error);
>  
> -  return NULL;
> +  return interp_data (self);
>  }
>  
>  static int
>  cli_interpreter_resume (void *data)
>  {
> +  struct cli_interp *cli = (struct cli_interp *) data;
>    struct ui_file *stream;
>  
>    /*sync_execution = 1; */
> @@ -144,17 +153,17 @@ cli_interpreter_resume (void *data)
>       previously writing to gdb_stdout, then set it to the new
>       gdb_stdout afterwards.  */
>  
> -  stream = cli_out_set_stream (cli_uiout, gdb_stdout);
> +  stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout);
>    if (stream != gdb_stdout)
>      {
> -      cli_out_set_stream (cli_uiout, stream);
> +      cli_out_set_stream (cli->cli_uiout, stream);
>        stream = NULL;
>      }
>  
>    gdb_setup_readline ();
>  
>    if (stream != NULL)
> -    cli_out_set_stream (cli_uiout, gdb_stdout);
> +    cli_out_set_stream (cli->cli_uiout, gdb_stdout);
>  
>    return 1;
>  }
> @@ -169,6 +178,7 @@ cli_interpreter_suspend (void *data)
>  static struct gdb_exception
>  cli_interpreter_exec (void *data, const char *command_str)
>  {
> +  struct cli_interp *cli = (struct cli_interp *) data;
>    struct ui_file *old_stream;
>    struct gdb_exception result;
>  
> @@ -184,9 +194,9 @@ cli_interpreter_exec (void *data, const char *command_str)
>  
>       It is important that it gets reset everytime, since the user
>       could set gdb to use a different interpreter.  */
> -  old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
> -  result = safe_execute_command (cli_uiout, str, 1);
> -  cli_out_set_stream (cli_uiout, old_stream);
> +  old_stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout);
> +  result = safe_execute_command (cli->cli_uiout, str, 1);
> +  cli_out_set_stream (cli->cli_uiout, old_stream);
>    return result;
>  }
>  
> @@ -222,7 +232,34 @@ safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty)
>  static struct ui_out *
>  cli_ui_out (struct interp *self)
>  {
> -  return cli_uiout;
> +  struct cli_interp *cli = (struct cli_interp *) interp_data (self);
> +
> +  return cli->cli_uiout;
> +}
> +
> +/* The CLI interpreter's vtable.  */
> +
> +static const struct interp_procs cli_interp_procs = {
> +  cli_interpreter_init,		/* init_proc */
> +  cli_interpreter_resume,	/* resume_proc */
> +  cli_interpreter_suspend,	/* suspend_proc */
> +  cli_interpreter_exec,		/* exec_proc */
> +  cli_ui_out,			/* ui_out_proc */
> +  NULL,                       	/* set_logging_proc */
> +  cli_command_loop            	/* command_loop_proc */
> +};
> +
> +/* Factory for CLI interpreters.  */
> +
> +static struct interp *
> +cli_interp_factory (const char *name, struct ui *ui)
> +{
> +  struct cli_interp *cli = XNEW (struct cli_interp);
> +
> +  /* Create a default uiout builder for the CLI.  */
> +  cli->cli_uiout = cli_out_new (gdb_stdout);
> +
> +  return interp_new (name, &cli_interp_procs, cli);
>  }
>  
>  /* Standard gdb initialization hook.  */
> @@ -231,19 +268,5 @@ extern initialize_file_ftype _initialize_cli_interp; /* -Wmissing-prototypes */
>  void
>  _initialize_cli_interp (void)
>  {
> -  static const struct interp_procs procs = {
> -    cli_interpreter_init,	/* init_proc */
> -    cli_interpreter_resume,	/* resume_proc */
> -    cli_interpreter_suspend,	/* suspend_proc */
> -    cli_interpreter_exec,	/* exec_proc */
> -    cli_ui_out,			/* ui_out_proc */
> -    NULL,                       /* set_logging_proc */
> -    cli_command_loop            /* command_loop_proc */
> -  };
> -
> -  /* Create a default uiout builder for the CLI.  */
> -  cli_uiout = cli_out_new (gdb_stdout);
> -  cli_interp = interp_new (INTERP_CONSOLE, &procs);
> -
> -  interp_add (cli_interp);
> +  interp_factory_register (INTERP_CONSOLE, cli_interp_factory);
>  }
> diff --git a/gdb/interps.c b/gdb/interps.c
> index 7f57132..ca8512b 100644
> --- a/gdb/interps.c
> +++ b/gdb/interps.c
> @@ -91,18 +91,20 @@ struct interp
>  
>  void _initialize_interpreter (void);
>  
> +static struct interp *interp_lookup_existing (const char *name);
> +
>  /* interp_new - This allocates space for a new interpreter,
>     fills the fields from the inputs, and returns a pointer to the
>     interpreter.  */
>  struct interp *
> -interp_new (const char *name, const struct interp_procs *procs)
> +interp_new (const char *name, const struct interp_procs *procs, void *data)
>  {
>    struct interp *new_interp;
>  
>    new_interp = XNEW (struct interp);
>  
>    new_interp->name = xstrdup (name);
> -  new_interp->data = NULL;
> +  new_interp->data = data;
>    new_interp->quiet_p = 0;
>    new_interp->procs = procs;
>    new_interp->inited = 0;
> @@ -113,6 +115,49 @@ interp_new (const char *name, const struct interp_procs *procs)
>    return new_interp;
>  }
>  
> +/* An interpreter factory.  Maps an interpreter name to the factory
> +   function that instantiates an interpreter by that name.  */
> +
> +struct interp_factory
> +{
> +  /* This is the name in "-i=INTERP" and "interpreter-exec INTERP".  */
> +  const char *name;
> +
> +  /* The function that creates the interpreter.  */
> +  interp_factory_func func;
> +};
> +
> +typedef struct interp_factory *interp_factory_p;
> +DEF_VEC_P(interp_factory_p);
> +
> +/* The registered interpreter factories.  */
> +static VEC(interp_factory_p) *interpreter_factories = NULL;
> +
> +/* See interps.h.  */
> +
> +void
> +interp_factory_register (const char *name, interp_factory_func func)
> +{
> +  struct interp_factory *f;
> +  int ix;
> +
> +  /* Assert that no factory for NAME is already registered.  */
> +  for (ix = 0;
> +       VEC_iterate (interp_factory_p, interpreter_factories, ix, f);
> +       ++ix)
> +    if (strcmp (f->name, name) == 0)
> +      {
> +	internal_error (__FILE__, __LINE__,
> +			_("interpreter factory already registered: \"%s\"\n"),
> +			name);
> +      }
> +
> +  f = XNEW (struct interp_factory);
> +  f->name = name;
> +  f->func = func;
> +  VEC_safe_push (interp_factory_p, interpreter_factories, f);
> +}
> +
>  /* Add interpreter INTERP to the gdb interpreter list.  The
>     interpreter must not have previously been added.  */
>  void
> @@ -120,7 +165,7 @@ interp_add (struct interp *interp)
>  {
>    struct ui_interp_info *ui_interp = get_current_interp_info ();
>  
> -  gdb_assert (interp_lookup (interp->name) == NULL);
> +  gdb_assert (interp_lookup_existing (interp->name) == NULL);
>  
>    interp->next = ui_interp->interp_list;
>    ui_interp->interp_list = interp;
> @@ -219,18 +264,15 @@ interp_set (struct interp *interp, int top_level)
>    return 1;
>  }
>  
> -/* interp_lookup - Looks up the interpreter for NAME.  If no such
> -   interpreter exists, return NULL, otherwise return a pointer to the
> -   interpreter.  */
> -struct interp *
> -interp_lookup (const char *name)
> +/* Look up the interpreter for NAME.  If no such interpreter exists,
> +   return NULL, otherwise return a pointer to the interpreter.  */
> +
> +static struct interp *
> +interp_lookup_existing (const char *name)
>  {
>    struct ui_interp_info *ui_interp = get_current_interp_info ();
>    struct interp *interp;
>  
> -  if (name == NULL || strlen (name) == 0)
> -    return NULL;
> -
>    for (interp = ui_interp->interp_list;
>         interp != NULL;
>         interp = interp->next)
> @@ -242,6 +284,37 @@ interp_lookup (const char *name)
>    return NULL;
>  }
>  
> +/* See interps.h.  */
> +
> +struct interp *
> +interp_lookup (const char *name)
> +{
> +  struct ui *ui = current_ui;
> +  struct interp_factory *factory;
> +  struct interp *interp;
> +  int ix;
> +
> +  if (name == NULL || strlen (name) == 0)
> +    return NULL;
> +
> +  /* Only create each interpreter once per top level.  */
> +  interp = interp_lookup_existing (name);
> +  if (interp != NULL)
> +    return interp;
> +
> +  for (ix = 0;
> +       VEC_iterate (interp_factory_p, interpreter_factories, ix, factory);
> +       ++ix)
> +    if (strcmp (factory->name, name) == 0)
> +      {
> +	interp = factory->func (name, ui);
> +	interp_add (interp);
> +	return interp;
> +      }
> +
> +  return NULL;
> +}
> +
>  /* Returns the current interpreter.  */
>  
>  struct ui_out *
> @@ -469,15 +542,15 @@ static VEC (char_ptr) *
>  interpreter_completer (struct cmd_list_element *ignore,
>  		       const char *text, const char *word)
>  {
> -  struct ui_interp_info *ui_interp = get_current_interp_info ();
> +  struct interp_factory *interp;
>    int textlen;
>    VEC (char_ptr) *matches = NULL;
> -  struct interp *interp;
> +  int ix;
>  
>    textlen = strlen (text);
> -  for (interp = ui_interp->interp_list;
> -       interp != NULL;
> -       interp = interp->next)
> +  for (ix = 0;
> +       VEC_iterate (interp_factory_p, interpreter_factories, ix, interp);
> +       ++ix)
>      {
>        if (strncmp (interp->name, text, textlen) == 0)
>  	{
> diff --git a/gdb/interps.h b/gdb/interps.h
> index f0badc5..3065fdf 100644
> --- a/gdb/interps.h
> +++ b/gdb/interps.h
> @@ -24,6 +24,17 @@
>  
>  struct ui_out;
>  struct interp;
> +struct ui;
> +
> +typedef struct interp *(*interp_factory_func) (const char *interp,

Nit:

In the functions of this type ({cli,mi,tui}_interp_factory), this parameter is named
"name", so you could as well name it "name" here as well.

> +					       struct ui *ui);

Even in the final result (with all patches applied), none of the factories
use the ui parameter, is it expected?

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 07/34] Make the intepreters output to all UIs
  2016-05-06 12:43 ` [PATCH v3 07/34] Make the intepreters output to all UIs Pedro Alves
@ 2016-05-19 15:16   ` Simon Marchi
  2016-05-26 18:12     ` Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-05-19 15:16 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-06 08:34 AM, Pedro Alves wrote:
> When we have multiple consoles, MI channels, etc., then we need to
> broadcast breakpoint hits, etc. to all UIs.  In the past, I've
> adjusted most of the run control to communicate events to the
> interpreters through observer notifications, so events would be
> properly sent to console and MI streams, in sync and async modes.
> 
> This patch does the next logical step -- have each interpreter's
> observers output interpreter-specific info to _all_ UIs.
> 
> Note that when we have multiple instances of active cli/tui
> interpreters, then the cli_interp and tui_interp globals no longer
> work.  This is addressed by this patch.
> 
> Also, the interpreters currently register some observers when resumed
> and remove them when suspended.  If we have multiple instances of the
> interpreters, and they can be suspended/resumed at different,
> independent times, that no longer works.  What we instead do is always
> install the observers, and then have the observers themselves know
> when to do nothing.
> 
> An earlier prototype of this series did the looping over struct UIs in
> common code, and then dispatched events to the interpreters through a
> matching interp_on_foo method for each observer.  That turned out a
> lot more complicated than the present solution, as we'd end up with
> having to create a new interp method every time some interpreter
> wanted to listen to some observer notification, resulting in a lot of
> duplicated make-work and more coupling than desirable.
> 
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* cli/cli-interp.c (cli_interp): Delete.
> 	(as_cli_interp): New function.
> 	(cli_on_normal_stop, cli_on_signal_received)
> 	(cli_on_end_stepping_range, cli_on_signal_exited, cli_on_exited)
> 	(cli_on_no_history): Send output to all CLI UIs.
> 	(cli_on_sync_execution_done, cli_on_command_error): Skip output if
> 	the top level interpreter is not a CLI.
> 	(cli_interpreter_init): Don't set cli_interp or install observers
> 	here.
> 	(_initialize_cli_interp): Install observers here.
> 	* event-top.c (main_ui_, ui_list): New globals.
> 	(current_ui): Point to main_ui_.
> 	(restore_ui_cleanup, switch_thru_all_uis_init)
> 	(switch_thru_all_uis_cond, switch_thru_all_uis_next): New
> 	functions.
> 	* mi/mi-interp.c (as_mi_interp): New function.
> 	(mi_interpreter_init): Don't install observers here.
> 	(mi_on_sync_execution_done): Skip output if the top level
> 	interpreter is not a MI.
> 	(mi_new_thread, mi_thread_exit, mi_record_changed)
> 	(mi_inferior_added, mi_inferior_appeared, mi_inferior_exit)
> 	(mi_inferior_removed): Send output to all MI UIs.
> 	(find_mi_interpreter, mi_interp_data): Delete.
> 	(find_mi_interp): New function.
> 	(mi_on_signal_received, mi_on_end_stepping_range)
> 	(mi_on_signal_exited, mi_on_exited, mi_on_no_history): Send output
> 	to all MI UIs.
> 	(mi_on_normal_stop): Rename to ...
> 	(mi_on_normal_stop_1): ... this.
> 	(mi_on_normal_stop): Reimplement, sending output to all MI UIs.
> 	(mi_traceframe_changed, mi_tsv_created, mi_tsv_deleted)
> 	(mi_tsv_modified, mi_breakpoint_created, mi_breakpoint_deleted)
> 	(mi_breakpoint_modified, mi_output_running_pid): Send output to
> 	all MI UIs.
> 	(mi_on_resume): Rename to ...
> 	(mi_on_resume_1): ... this.  Don't handle infcalls here.
> 	(mi_on_resume): Reimplement, sending output to all MI UIs.
> 	(mi_solib_loaded, mi_solib_unloaded, mi_command_param_changed)
> 	(mi_memory_changed): Send output to all MI UIs.
> 	(report_initial_inferior): Install observers here.
> 	* top.h (struct ui) <next>: New field.
> 	(ui_list): Declare.
> 	(struct switch_thru_all_uis): New.
> 	(switch_thru_all_uis_init, switch_thru_all_uis_cond)
> 	(switch_thru_all_uis_next): Declare.
> 	(SWITCH_THRU_ALL_UIS): New macro.
> 	* tui/tui-interp.c (tui_interp): Delete global.
> 	(as_tui_interp): New function.
> 	(tui_on_normal_stop, tui_on_signal_received)
> 	(tui_on_end_stepping_range, tui_on_signal_exited, tui_on_exited)
> 	(tui_on_no_history): Send output to all TUI UIs.
> 	(tui_on_sync_execution_done, tui_on_command_error): Skip output if
> 	the top level interpreter is not a TUI.
> 	(tui_init): Don't set tui_interp or install observers here.
> 	(_initialize_tui_interp): Install observers here.
> ---
>  gdb/cli/cli-interp.c | 127 +++++--
>  gdb/event-top.c      |  51 ++-
>  gdb/mi/mi-interp.c   | 919 ++++++++++++++++++++++++++++++++-------------------
>  gdb/top.h            |  29 ++
>  gdb/tui/tui-interp.c | 127 +++++--
>  5 files changed, 841 insertions(+), 412 deletions(-)
> 
> diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
> index ac12a4c..cd33dd2 100644
> --- a/gdb/cli/cli-interp.c
> +++ b/gdb/cli/cli-interp.c
> @@ -33,8 +33,16 @@ struct cli_interp
>    struct ui_out *cli_uiout;
>  };
>  
> -/* The interpreter for the console interpreter.  */
> -static struct interp *cli_interp;
> +/* Returns the INTERP's data cast as cli_interp if INTERP is a CLI,
> +   and returns NULL otherwise.  */
> +
> +static struct cli_interp *
> +as_cli_interp (struct interp *interp)
> +{
> +  if (strcmp (interp_name (interp), INTERP_CONSOLE) == 0)
> +    return (struct cli_interp *) interp_data (interp);
> +  return NULL;
> +}
>  
>  /* Longjmp-safe wrapper for "execute_command".  */
>  static struct gdb_exception safe_execute_command (struct ui_out *uiout,
> @@ -50,10 +58,17 @@ static struct gdb_exception safe_execute_command (struct ui_out *uiout,
>  static void
>  cli_on_normal_stop (struct bpstats *bs, int print_frame)
>  {
> -  if (!interp_quiet_p (cli_interp))
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
>      {
> +      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +      if (cli == NULL)
> +	continue;
> +
>        if (print_frame)
> -	print_stop_event (interp_ui_out (cli_interp));
> +	print_stop_event (cli->cli_uiout);
>      }
>  }
>  
> @@ -62,8 +77,17 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame)
>  static void
>  cli_on_signal_received (enum gdb_signal siggnal)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    print_signal_received_reason (interp_ui_out (cli_interp), siggnal);
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +      if (cli == NULL)
> +	continue;
> +
> +      print_signal_received_reason (cli->cli_uiout, siggnal);
> +    }
>  }
>  
>  /* Observer for the end_stepping_range notification.  */
> @@ -71,8 +95,17 @@ cli_on_signal_received (enum gdb_signal siggnal)
>  static void
>  cli_on_end_stepping_range (void)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    print_end_stepping_range_reason (interp_ui_out (cli_interp));
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +      if (cli == NULL)
> +	continue;
> +
> +      print_end_stepping_range_reason (cli->cli_uiout);
> +    }
>  }
>  
>  /* Observer for the signalled notification.  */
> @@ -80,8 +113,17 @@ cli_on_end_stepping_range (void)
>  static void
>  cli_on_signal_exited (enum gdb_signal siggnal)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    print_signal_exited_reason (interp_ui_out (cli_interp), siggnal);
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +      if (cli == NULL)
> +	continue;
> +
> +      print_signal_exited_reason (cli->cli_uiout, siggnal);
> +    }
>  }
>  
>  /* Observer for the exited notification.  */
> @@ -89,8 +131,17 @@ cli_on_signal_exited (enum gdb_signal siggnal)
>  static void
>  cli_on_exited (int exitstatus)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    print_exited_reason (interp_ui_out (cli_interp), exitstatus);
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +      if (cli == NULL)
> +	continue;
> +
> +      print_exited_reason (cli->cli_uiout, exitstatus);
> +    }
>  }
>  
>  /* Observer for the no_history notification.  */
> @@ -98,8 +149,17 @@ cli_on_exited (int exitstatus)
>  static void
>  cli_on_no_history (void)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    print_no_history_reason (interp_ui_out (cli_interp));
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +      if (cli == NULL)
> +	continue;
> +
> +      print_no_history_reason (cli->cli_uiout);
> +    }
>  }
>  
>  /* Observer for the sync_execution_done notification.  */
> @@ -107,8 +167,12 @@ cli_on_no_history (void)
>  static void
>  cli_on_sync_execution_done (void)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    display_gdb_prompt (NULL);
> +  struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +  if (cli == NULL)
> +    return;
> +
> +  display_gdb_prompt (NULL);
>  }
>  
>  /* Observer for the command_error notification.  */
> @@ -116,8 +180,12 @@ cli_on_sync_execution_done (void)
>  static void
>  cli_on_command_error (void)
>  {
> -  if (!interp_quiet_p (cli_interp))
> -    display_gdb_prompt (NULL);
> +  struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
> +
> +  if (cli == NULL)
> +    return;
> +
> +  display_gdb_prompt (NULL);
>  }
>  
>  /* These implement the cli out interpreter: */
> @@ -125,19 +193,6 @@ cli_on_command_error (void)
>  static void *
>  cli_interpreter_init (struct interp *self, int top_level)
>  {
> -  if (top_level)
> -    cli_interp = self;
> -
> -  /* If changing this, remember to update tui-interp.c as well.  */
> -  observer_attach_normal_stop (cli_on_normal_stop);
> -  observer_attach_end_stepping_range (cli_on_end_stepping_range);
> -  observer_attach_signal_received (cli_on_signal_received);
> -  observer_attach_signal_exited (cli_on_signal_exited);
> -  observer_attach_exited (cli_on_exited);
> -  observer_attach_no_history (cli_on_no_history);
> -  observer_attach_sync_execution_done (cli_on_sync_execution_done);
> -  observer_attach_command_error (cli_on_command_error);
> -
>    return interp_data (self);
>  }
>  
> @@ -269,4 +324,14 @@ void
>  _initialize_cli_interp (void)
>  {
>    interp_factory_register (INTERP_CONSOLE, cli_interp_factory);
> +
> +  /* If changing this, remember to update tui-interp.c as well.  */
> +  observer_attach_normal_stop (cli_on_normal_stop);
> +  observer_attach_end_stepping_range (cli_on_end_stepping_range);
> +  observer_attach_signal_received (cli_on_signal_received);
> +  observer_attach_signal_exited (cli_on_signal_exited);
> +  observer_attach_exited (cli_on_exited);
> +  observer_attach_no_history (cli_on_no_history);
> +  observer_attach_sync_execution_done (cli_on_sync_execution_done);
> +  observer_attach_command_error (cli_on_command_error);
>  }
> diff --git a/gdb/event-top.c b/gdb/event-top.c
> index 664543c..c6e3b7e 100644
> --- a/gdb/event-top.c
> +++ b/gdb/event-top.c
> @@ -437,8 +437,55 @@ top_level_prompt (void)
>    return xstrdup (prompt);
>  }
>  
> -static struct ui current_ui_;
> -struct ui *current_ui = &current_ui_;
> +/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> +   It always exists and is created automatically when GDB starts
> +   up.  */
> +static struct ui main_ui_;
> +
> +struct ui *current_ui = &main_ui_;
> +struct ui *ui_list = &main_ui_;
> +
> +/* Cleanup that restores the current UI.  */
> +
> +static void
> +restore_ui_cleanup (void *data)
> +{
> +  current_ui = (struct ui *) data;
> +}
> +
> +/* See top.h.  */
> +
> +void
> +switch_thru_all_uis_init (struct switch_thru_all_uis *state)
> +{
> +  state->iter = ui_list;
> +  state->old_chain = make_cleanup (restore_ui_cleanup, current_ui);
> +}
> +
> +/* See top.h.  */
> +
> +int
> +switch_thru_all_uis_cond (struct switch_thru_all_uis *state)
> +{
> +  if (state->iter != NULL)
> +    {
> +      current_ui = state->iter;
> +      return 1;
> +    }
> +  else
> +    {
> +      do_cleanups (state->old_chain);
> +      return 0;
> +    }
> +}
> +
> +/* See top.h.  */
> +
> +void
> +switch_thru_all_uis_next (struct switch_thru_all_uis *state)
> +{
> +  state->iter = state->iter->next;
> +}
>  
>  /* Get a pointer to the current UI's line buffer.  This is used to
>     construct a whole line of input from partial input.  */
> diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
> index 8ba6110..f9820cb 100644
> --- a/gdb/mi/mi-interp.c
> +++ b/gdb/mi/mi-interp.c
> @@ -88,6 +88,17 @@ static void mi_on_sync_execution_done (void);
>  
>  static int report_initial_inferior (struct inferior *inf, void *closure);
>  
> +/* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and
> +   returns NULL otherwise.  */
> +
> +static struct mi_interp *
> +as_mi_interp (struct interp *interp)
> +{
> +  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
> +    return (struct mi_interp *) interp_data (interp);
> +  return NULL;
> +}
> +
>  static void *
>  mi_interpreter_init (struct interp *interp, int top_level)
>  {
> @@ -127,39 +138,8 @@ mi_interpreter_init (struct interp *interp, int top_level)
>    mi->mi_uiout = mi_out_new (mi_version);
>    mi->cli_uiout = cli_out_new (mi->out);
>  
> -  /* There are installed even if MI is not the top level interpreter.
> -     The callbacks themselves decide whether to be skipped.  */
> -  observer_attach_signal_received (mi_on_signal_received);
> -  observer_attach_end_stepping_range (mi_on_end_stepping_range);
> -  observer_attach_signal_exited (mi_on_signal_exited);
> -  observer_attach_exited (mi_on_exited);
> -  observer_attach_no_history (mi_on_no_history);
> -
>    if (top_level)
>      {
> -      observer_attach_new_thread (mi_new_thread);
> -      observer_attach_thread_exit (mi_thread_exit);
> -      observer_attach_inferior_added (mi_inferior_added);
> -      observer_attach_inferior_appeared (mi_inferior_appeared);
> -      observer_attach_inferior_exit (mi_inferior_exit);
> -      observer_attach_inferior_removed (mi_inferior_removed);
> -      observer_attach_record_changed (mi_record_changed);
> -      observer_attach_normal_stop (mi_on_normal_stop);
> -      observer_attach_target_resumed (mi_on_resume);
> -      observer_attach_solib_loaded (mi_solib_loaded);
> -      observer_attach_solib_unloaded (mi_solib_unloaded);
> -      observer_attach_about_to_proceed (mi_about_to_proceed);
> -      observer_attach_traceframe_changed (mi_traceframe_changed);
> -      observer_attach_tsv_created (mi_tsv_created);
> -      observer_attach_tsv_deleted (mi_tsv_deleted);
> -      observer_attach_tsv_modified (mi_tsv_modified);
> -      observer_attach_breakpoint_created (mi_breakpoint_created);
> -      observer_attach_breakpoint_deleted (mi_breakpoint_deleted);
> -      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
>  	 case future version of GDB creates more than one inferior
> @@ -311,6 +291,12 @@ mi_execute_command_wrapper (const char *cmd)
>  static void
>  mi_on_sync_execution_done (void)
>  {
> +  struct ui *ui = current_ui;
> +  struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +
> +  if (mi == NULL)
> +    return;
> +
>    /* If MI is sync, then output the MI prompt now, indicating we're
>       ready for further input.  */
>    if (!mi_async_p ())
> @@ -356,45 +342,56 @@ mi_command_loop (void *data)
>  static void
>  mi_new_thread (struct thread_info *t)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
>    struct inferior *inf = find_inferior_ptid (t->ptid);
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    gdb_assert (inf);
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel, 
> -		      "thread-created,id=\"%d\",group-id=\"i%d\"",
> -		      t->global_num, inf->num);
> -  gdb_flush (mi->event_channel);
> +      if (mi == NULL)
> +	continue;
>  
> -  do_cleanups (old_chain);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      fprintf_unfiltered (mi->event_channel,
> +			  "thread-created,id=\"%d\",group-id=\"i%d\"",
> +			  t->global_num, inf->num);
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static void
>  mi_thread_exit (struct thread_info *t, int silent)
>  {
> -  struct mi_interp *mi;
> -  struct inferior *inf;
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (silent)
>      return;
>  
> -  inf = find_inferior_ptid (t->ptid);
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  mi = (struct mi_interp *) top_level_interpreter_data ();
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +      if (mi == NULL)
> +	continue;
>  
> -  fprintf_unfiltered (mi->event_channel, 
> -		      "thread-exited,id=\"%d\",group-id=\"i%d\"",
> -		      t->global_num, inf->num);
> -  gdb_flush (mi->event_channel);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +      fprintf_unfiltered (mi->event_channel,
> +			  "thread-exited,id=\"%d\",group-id=\"i%d\"",
> +			  t->global_num, t->inf->num);
> +      gdb_flush (mi->event_channel);
>  
> -  do_cleanups (old_chain);
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification on changing the state of record.  */
> @@ -402,122 +399,155 @@ mi_thread_exit (struct thread_info *t, int silent)
>  static void
>  mi_record_changed (struct inferior *inferior, int started)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,  "record-%s,thread-group=\"i%d\"",
> -		      started ? "started" : "stopped", inferior->num);
> +      if (mi == NULL)
> +	continue;
>  
> -  gdb_flush (mi->event_channel);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  do_cleanups (old_chain);
> +      fprintf_unfiltered (mi->event_channel,  "record-%s,thread-group=\"i%d\"",
> +			  started ? "started" : "stopped", inferior->num);
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static void
>  mi_inferior_added (struct inferior *inf)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct interp *interp;
> +      struct mi_interp *mi;
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,
> -		      "thread-group-added,id=\"i%d\"",
> -		      inf->num);
> -  gdb_flush (mi->event_channel);
> +      /* We'll be called once for the initial inferior, before the top
> +	 level interpreter is set.  */
> +      interp = top_level_interpreter ();
> +      if (interp == NULL)
> +	continue;
>  
> -  do_cleanups (old_chain);
> +      mi = as_mi_interp (interp);
> +      if (mi == NULL)
> +	continue;
> +
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      fprintf_unfiltered (mi->event_channel,
> +			  "thread-group-added,id=\"i%d\"",
> +			  inf->num);
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static void
>  mi_inferior_appeared (struct inferior *inf)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,
> -		      "thread-group-started,id=\"i%d\",pid=\"%d\"",
> -		      inf->num, inf->pid);
> -  gdb_flush (mi->event_channel);
> +      if (mi == NULL)
> +	continue;
>  
> -  do_cleanups (old_chain);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      fprintf_unfiltered (mi->event_channel,
> +			  "thread-group-started,id=\"i%d\",pid=\"%d\"",
> +			  inf->num, inf->pid);
> +      gdb_flush (mi->event_channel);
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static void
>  mi_inferior_exit (struct inferior *inf)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  if (inf->has_exit_code)
> -    fprintf_unfiltered (mi->event_channel,
> -			"thread-group-exited,id=\"i%d\",exit-code=\"%s\"",
> -			inf->num, int_string (inf->exit_code, 8, 0, 0, 1));
> -  else
> -    fprintf_unfiltered (mi->event_channel,
> -			"thread-group-exited,id=\"i%d\"", inf->num);
> -  gdb_flush (mi->event_channel);
> +      if (mi == NULL)
> +	continue;
>  
> -  do_cleanups (old_chain);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      if (inf->has_exit_code)
> +	fprintf_unfiltered (mi->event_channel,
> +			    "thread-group-exited,id=\"i%d\",exit-code=\"%s\"",
> +			    inf->num, int_string (inf->exit_code, 8, 0, 0, 1));
> +      else
> +	fprintf_unfiltered (mi->event_channel,
> +			    "thread-group-exited,id=\"i%d\"", inf->num);
> +
> +      gdb_flush (mi->event_channel);
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static void
>  mi_inferior_removed (struct inferior *inf)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,
> -		      "thread-group-removed,id=\"i%d\"",
> -		      inf->num);
> -  gdb_flush (mi->event_channel);
> +      if (mi == NULL)
> +	continue;
>  
> -  do_cleanups (old_chain);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      fprintf_unfiltered (mi->event_channel,
> +			  "thread-group-removed,id=\"i%d\"",
> +			  inf->num);
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Return the MI interpreter, if it is active -- either because it's
>     the top-level interpreter or the interpreter executing the current
>     command.  Returns NULL if the MI interpreter is not being used.  */
>  
> -static struct interp *
> -find_mi_interpreter (void)
> +static struct mi_interp *
> +find_mi_interp (void)
>  {
> -  struct interp *interp;
> -
> -  interp = top_level_interpreter ();
> -  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
> -    return interp;
> -
> -  interp = command_interp ();
> -  if (ui_out_is_mi_like_p (interp_ui_out (interp)))
> -    return interp;
> -
> -  return NULL;
> -}
> +  struct mi_interp *mi;
>  
> -/* Return the MI_INTERP structure of the active MI interpreter.
> -   Returns NULL if MI is not active.  */
> +  mi = as_mi_interp (top_level_interpreter ());
> +  if (mi != NULL)
> +    return mi;
>  
> -static struct mi_interp *
> -mi_interp_data (void)
> -{
> -  struct interp *interp = find_mi_interpreter ();
> +  mi = as_mi_interp (command_interp ());
> +  if (mi != NULL)
> +    return mi;
>  
> -  if (interp != NULL)
> -    return (struct mi_interp *) interp_data (interp);
>    return NULL;
>  }
>  
> @@ -530,13 +560,18 @@ mi_interp_data (void)
>  static void
>  mi_on_signal_received (enum gdb_signal siggnal)
>  {
> -  struct mi_interp *mi = mi_interp_data ();
> +  struct switch_thru_all_uis state;
>  
> -  if (mi == NULL)
> -    return;
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = find_mi_interp ();
> +
> +      if (mi == NULL)
> +	continue;
>  
> -  print_signal_received_reason (mi->mi_uiout, siggnal);
> -  print_signal_received_reason (mi->cli_uiout, siggnal);
> +      print_signal_received_reason (mi->mi_uiout, siggnal);
> +      print_signal_received_reason (mi->cli_uiout, siggnal);
> +    }
>  }
>  
>  /* Observer for the end_stepping_range notification.  */
> @@ -544,13 +579,18 @@ mi_on_signal_received (enum gdb_signal siggnal)
>  static void
>  mi_on_end_stepping_range (void)
>  {
> -  struct mi_interp *mi = mi_interp_data ();
> +  struct switch_thru_all_uis state;
>  
> -  if (mi == NULL)
> -    return;
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = find_mi_interp ();
> +
> +      if (mi == NULL)
> +	continue;
>  
> -  print_end_stepping_range_reason (mi->mi_uiout);
> -  print_end_stepping_range_reason (mi->cli_uiout);
> +      print_end_stepping_range_reason (mi->mi_uiout);
> +      print_end_stepping_range_reason (mi->cli_uiout);
> +    }
>  }
>  
>  /* Observer for the signal_exited notification.  */
> @@ -558,13 +598,18 @@ mi_on_end_stepping_range (void)
>  static void
>  mi_on_signal_exited (enum gdb_signal siggnal)
>  {
> -  struct mi_interp *mi = mi_interp_data ();
> +  struct switch_thru_all_uis state;
>  
> -  if (mi == NULL)
> -    return;
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = find_mi_interp ();
> +
> +      if (mi == NULL)
> +	continue;
>  
> -  print_signal_exited_reason (mi->mi_uiout, siggnal);
> -  print_signal_exited_reason (mi->cli_uiout, siggnal);
> +      print_signal_exited_reason (mi->mi_uiout, siggnal);
> +      print_signal_exited_reason (mi->cli_uiout, siggnal);
> +    }
>  }
>  
>  /* Observer for the exited notification.  */
> @@ -572,13 +617,18 @@ mi_on_signal_exited (enum gdb_signal siggnal)
>  static void
>  mi_on_exited (int exitstatus)
>  {
> -  struct mi_interp *mi = mi_interp_data ();
> +  struct switch_thru_all_uis state;
>  
> -  if (mi == NULL)
> -    return;
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = find_mi_interp ();
> +
> +      if (mi == NULL)
> +	continue;
>  
> -  print_exited_reason (mi->mi_uiout, exitstatus);
> -  print_exited_reason (mi->cli_uiout, exitstatus);
> +      print_exited_reason (mi->mi_uiout, exitstatus);
> +      print_exited_reason (mi->cli_uiout, exitstatus);
> +    }
>  }
>  
>  /* Observer for the no_history notification.  */
> @@ -586,17 +636,22 @@ mi_on_exited (int exitstatus)
>  static void
>  mi_on_no_history (void)
>  {
> -  struct mi_interp *mi = mi_interp_data ();
> +  struct switch_thru_all_uis state;
>  
> -  if (mi == NULL)
> -    return;
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = find_mi_interp ();
> +
> +      if (mi == NULL)
> +	continue;
>  
> -  print_no_history_reason (mi->mi_uiout);
> -  print_no_history_reason (mi->cli_uiout);
> +      print_no_history_reason (mi->mi_uiout);
> +      print_no_history_reason (mi->cli_uiout);
> +    }
>  }
>  
>  static void
> -mi_on_normal_stop (struct bpstats *bs, int print_frame)
> +mi_on_normal_stop_1 (struct bpstats *bs, int print_frame)
>  {
>    /* Since this can be called when CLI command is executing,
>       using cli interpreter, be sure to use MI uiout for output,
> @@ -677,6 +732,20 @@ mi_on_normal_stop (struct bpstats *bs, int print_frame)
>  }
>  
>  static void
> +mi_on_normal_stop (struct bpstats *bs, int print_frame)
> +{
> +  struct switch_thru_all_uis state;
> +
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      if (as_mi_interp (top_level_interpreter ()) == NULL)
> +	continue;
> +
> +      mi_on_normal_stop_1 (bs, print_frame);
> +    }
> +}
> +
> +static void
>  mi_about_to_proceed (void)
>  {
>    /* Suppress output while calling an inferior function.  */
> @@ -707,25 +776,33 @@ struct mi_suppress_notification mi_suppress_notification =
>  static void
>  mi_traceframe_changed (int tfnum, int tpnum)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (mi_suppress_notification.traceframe)
>      return;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  if (tfnum >= 0)
> -    fprintf_unfiltered (mi->event_channel, "traceframe-changed,"
> -			"num=\"%d\",tracepoint=\"%d\"\n",
> -			tfnum, tpnum);
> -  else
> -    fprintf_unfiltered (mi->event_channel, "traceframe-changed,end");
> +      if (mi == NULL)
> +	continue;
>  
> -  gdb_flush (mi->event_channel);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  do_cleanups (old_chain);
> +      if (tfnum >= 0)
> +	fprintf_unfiltered (mi->event_channel, "traceframe-changed,"
> +			    "num=\"%d\",tracepoint=\"%d\"\n",
> +			    tfnum, tpnum);
> +      else
> +	fprintf_unfiltered (mi->event_channel, "traceframe-changed,end");
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification on creating a trace state variable.  */
> @@ -733,19 +810,27 @@ mi_traceframe_changed (int tfnum, int tpnum)
>  static void
>  mi_tsv_created (const struct trace_state_variable *tsv)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel, "tsv-created,"
> -		      "name=\"%s\",initial=\"%s\"\n",
> -		      tsv->name, plongest (tsv->initial_value));
> +      if (mi == NULL)
> +	continue;
>  
> -  gdb_flush (mi->event_channel);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  do_cleanups (old_chain);
> +      fprintf_unfiltered (mi->event_channel, "tsv-created,"
> +			  "name=\"%s\",initial=\"%s\"\n",
> +			  tsv->name, plongest (tsv->initial_value));
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification on deleting a trace state variable.  */
> @@ -753,21 +838,29 @@ mi_tsv_created (const struct trace_state_variable *tsv)
>  static void
>  mi_tsv_deleted (const struct trace_state_variable *tsv)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  if (tsv != NULL)
> -    fprintf_unfiltered (mi->event_channel, "tsv-deleted,"
> -			"name=\"%s\"\n", tsv->name);
> -  else
> -    fprintf_unfiltered (mi->event_channel, "tsv-deleted\n");
> +      if (mi == NULL)
> +	continue;
>  
> -  gdb_flush (mi->event_channel);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  do_cleanups (old_chain);
> +      if (tsv != NULL)
> +	fprintf_unfiltered (mi->event_channel, "tsv-deleted,"
> +			    "name=\"%s\"\n", tsv->name);
> +      else
> +	fprintf_unfiltered (mi->event_channel, "tsv-deleted\n");
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification on modifying a trace state variable.  */
> @@ -775,29 +868,39 @@ mi_tsv_deleted (const struct trace_state_variable *tsv)
>  static void
>  mi_tsv_modified (const struct trace_state_variable *tsv)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct ui_out *mi_uiout;
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,
> -		      "tsv-modified");
> +      if (mi == NULL)
> +	continue;
>  
> -  ui_out_redirect (mi_uiout, mi->event_channel);
> +      mi_uiout = interp_ui_out (top_level_interpreter ());
>  
> -  ui_out_field_string (mi_uiout, "name", tsv->name);
> -  ui_out_field_string (mi_uiout, "initial",
> -		       plongest (tsv->initial_value));
> -  if (tsv->value_known)
> -    ui_out_field_string (mi_uiout, "current", plongest (tsv->value));
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  ui_out_redirect (mi_uiout, NULL);
> +      fprintf_unfiltered (mi->event_channel,
> +			  "tsv-modified");
>  
> -  gdb_flush (mi->event_channel);
> +      ui_out_redirect (mi_uiout, mi->event_channel);
>  
> -  do_cleanups (old_chain);
> +      ui_out_field_string (mi_uiout, "name", tsv->name);
> +      ui_out_field_string (mi_uiout, "initial",
> +			   plongest (tsv->initial_value));
> +      if (tsv->value_known)
> +	ui_out_field_string (mi_uiout, "current", plongest (tsv->value));
> +
> +      ui_out_redirect (mi_uiout, NULL);
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification about a created breakpoint.  */
> @@ -805,9 +908,7 @@ mi_tsv_modified (const struct trace_state_variable *tsv)
>  static void
>  mi_breakpoint_created (struct breakpoint *b)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (mi_suppress_notification.breakpoint)
>      return;
> @@ -815,33 +916,45 @@ mi_breakpoint_created (struct breakpoint *b)
>    if (b->number <= 0)
>      return;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> -
> -  fprintf_unfiltered (mi->event_channel,
> -		      "breakpoint-created");
> -  /* We want the output from gdb_breakpoint_query to go to
> -     mi->event_channel.  One approach would be to just call
> -     gdb_breakpoint_query, and then use mi_out_put to send the current
> -     content of mi_outout into mi->event_channel.  However, that will
> -     break if anything is output to mi_uiout prior to calling the
> -     breakpoint_created notifications.  So, we use
> -     ui_out_redirect.  */
> -  ui_out_redirect (mi_uiout, mi->event_channel);
> -  TRY
> +  SWITCH_THRU_ALL_UIS (state)
>      {
> -      gdb_breakpoint_query (mi_uiout, b->number, NULL);
> -    }
> -  CATCH (e, RETURN_MASK_ERROR)
> -    {
> -    }
> -  END_CATCH
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct ui_out *mi_uiout;
> +      struct cleanup *old_chain;
> +
> +      if (mi == NULL)
> +	continue;
> +
> +      mi_uiout = interp_ui_out (top_level_interpreter ());
> +
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      fprintf_unfiltered (mi->event_channel,
> +			  "breakpoint-created");
> +      /* We want the output from gdb_breakpoint_query to go to
> +	 mi->event_channel.  One approach would be to just call
> +	 gdb_breakpoint_query, and then use mi_out_put to send the current
> +	 content of mi_outout into mi->event_channel.  However, that will
> +	 break if anything is output to mi_uiout prior to calling the
> +	 breakpoint_created notifications.  So, we use
> +	 ui_out_redirect.  */
> +      ui_out_redirect (mi_uiout, mi->event_channel);
> +      TRY
> +	{
> +	  gdb_breakpoint_query (mi_uiout, b->number, NULL);
> +	}
> +      CATCH (e, RETURN_MASK_ERROR)
> +	{
> +	}
> +      END_CATCH
>  
> -  ui_out_redirect (mi_uiout, NULL);
> +      ui_out_redirect (mi_uiout, NULL);
>  
> -  gdb_flush (mi->event_channel);
> +      gdb_flush (mi->event_channel);
>  
> -  do_cleanups (old_chain);
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification about deleted breakpoint.  */
> @@ -849,8 +962,7 @@ mi_breakpoint_created (struct breakpoint *b)
>  static void
>  mi_breakpoint_deleted (struct breakpoint *b)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (mi_suppress_notification.breakpoint)
>      return;
> @@ -858,15 +970,24 @@ mi_breakpoint_deleted (struct breakpoint *b)
>    if (b->number <= 0)
>      return;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"",
> -		      b->number);
> +      if (mi == NULL)
> +	continue;
>  
> -  gdb_flush (mi->event_channel);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  do_cleanups (old_chain);
> +      fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"",
> +			  b->number);
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification about modified breakpoint.  */
> @@ -874,9 +995,7 @@ mi_breakpoint_deleted (struct breakpoint *b)
>  static void
>  mi_breakpoint_modified (struct breakpoint *b)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (mi_suppress_notification.breakpoint)
>      return;
> @@ -884,44 +1003,61 @@ mi_breakpoint_modified (struct breakpoint *b)
>    if (b->number <= 0)
>      return;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> -
> -  fprintf_unfiltered (mi->event_channel,
> -		      "breakpoint-modified");
> -  /* We want the output from gdb_breakpoint_query to go to
> -     mi->event_channel.  One approach would be to just call
> -     gdb_breakpoint_query, and then use mi_out_put to send the current
> -     content of mi_outout into mi->event_channel.  However, that will
> -     break if anything is output to mi_uiout prior to calling the
> -     breakpoint_created notifications.  So, we use
> -     ui_out_redirect.  */
> -  ui_out_redirect (mi_uiout, mi->event_channel);
> -  TRY
> +  SWITCH_THRU_ALL_UIS (state)
>      {
> -      gdb_breakpoint_query (mi_uiout, b->number, NULL);
> -    }
> -  CATCH (e, RETURN_MASK_ERROR)
> -    {
> -    }
> -  END_CATCH
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
> +
> +      if (mi == NULL)
> +	continue;
> +
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +      fprintf_unfiltered (mi->event_channel,
> +			  "breakpoint-modified");
> +      /* We want the output from gdb_breakpoint_query to go to
> +	 mi->event_channel.  One approach would be to just call
> +	 gdb_breakpoint_query, and then use mi_out_put to send the current
> +	 content of mi_outout into mi->event_channel.  However, that will
> +	 break if anything is output to mi_uiout prior to calling the
> +	 breakpoint_created notifications.  So, we use
> +	 ui_out_redirect.  */
> +      ui_out_redirect (mi->mi_uiout, mi->event_channel);
> +      TRY
> +	{
> +	  gdb_breakpoint_query (mi->mi_uiout, b->number, NULL);
> +	}
> +      CATCH (e, RETURN_MASK_ERROR)
> +	{
> +	}
> +      END_CATCH
>  
> -  ui_out_redirect (mi_uiout, NULL);
> +      ui_out_redirect (mi->mi_uiout, NULL);
>  
> -  gdb_flush (mi->event_channel);
> +      gdb_flush (mi->event_channel);
>  
> -  do_cleanups (old_chain);
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static int
>  mi_output_running_pid (struct thread_info *info, void *arg)
>  {
>    ptid_t *ptid = (ptid_t *) arg;
> +  struct switch_thru_all_uis state;
>  
> -  if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
> -    fprintf_unfiltered (raw_stdout,
> -			"*running,thread-id=\"%d\"\n",
> -			info->global_num);
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +
> +      if (mi == NULL)
> +	continue;
> +
> +      if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
> +	fprintf_unfiltered (raw_stdout,
> +			    "*running,thread-id=\"%d\"\n",
> +			    info->global_num);
> +    }
>  
>    return 0;
>  }
> @@ -939,19 +1075,8 @@ mi_inferior_count (struct inferior *inf, void *arg)
>  }
>  
>  static void
> -mi_on_resume (ptid_t ptid)
> +mi_on_resume_1 (ptid_t ptid)
>  {
> -  struct thread_info *tp = NULL;
> -
> -  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
> -    tp = inferior_thread ();
> -  else
> -    tp = find_thread_ptid (ptid);
> -
> -  /* Suppress output while calling an inferior function.  */
> -  if (tp->control.in_infcall)
> -    return;
> -
>    /* To cater for older frontends, emit ^running, but do it only once
>       per each command.  We do it here, since at this point we know
>       that the target was successfully resumed, and in non-async mode,
> @@ -1006,64 +1131,116 @@ mi_on_resume (ptid_t ptid)
>  }
>  
>  static void
> -mi_solib_loaded (struct so_list *solib)
> +mi_on_resume (ptid_t ptid)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *uiout = interp_ui_out (top_level_interpreter ());
> -  struct cleanup *old_chain;
> -
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  struct thread_info *tp = NULL;
> +  struct switch_thru_all_uis state;
>  
> -  fprintf_unfiltered (mi->event_channel, "library-loaded");
> +  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
> +    tp = inferior_thread ();
> +  else
> +    tp = find_thread_ptid (ptid);
>  
> -  ui_out_redirect (uiout, mi->event_channel);
> +  /* Suppress output while calling an inferior function.  */
> +  if (tp->control.in_infcall)
> +    return;
>  
> -  ui_out_field_string (uiout, "id", solib->so_original_name);
> -  ui_out_field_string (uiout, "target-name", solib->so_original_name);
> -  ui_out_field_string (uiout, "host-name", solib->so_name);
> -  ui_out_field_int (uiout, "symbols-loaded", solib->symbols_loaded);
> -  if (!gdbarch_has_global_solist (target_gdbarch ()))
> +  SWITCH_THRU_ALL_UIS (state)
>      {
> -      ui_out_field_fmt (uiout, "thread-group", "i%d",
> -			current_inferior ()->num);
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct cleanup *old_chain;
> +
> +      if (mi == NULL)
> +	continue;
> +
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      mi_on_resume_1 (ptid);
> +
> +      do_cleanups (old_chain);
>      }
> +}
>  
> -  ui_out_redirect (uiout, NULL);
> +static void
> +mi_solib_loaded (struct so_list *solib)
> +{
> +  struct switch_thru_all_uis state;
>  
> -  gdb_flush (mi->event_channel);
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct ui_out *uiout;
> +      struct cleanup *old_chain;
>  
> -  do_cleanups (old_chain);
> +      if (mi == NULL)
> +	continue;
> +
> +      uiout = interp_ui_out (top_level_interpreter ());
> +
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
> +
> +      fprintf_unfiltered (mi->event_channel, "library-loaded");
> +
> +      ui_out_redirect (uiout, mi->event_channel);
> +
> +      ui_out_field_string (uiout, "id", solib->so_original_name);
> +      ui_out_field_string (uiout, "target-name", solib->so_original_name);
> +      ui_out_field_string (uiout, "host-name", solib->so_name);
> +      ui_out_field_int (uiout, "symbols-loaded", solib->symbols_loaded);
> +      if (!gdbarch_has_global_solist (target_gdbarch ()))
> +	{
> +	  ui_out_field_fmt (uiout, "thread-group", "i%d",
> +			    current_inferior ()->num);
> +	}
> +
> +      ui_out_redirect (uiout, NULL);
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static void
>  mi_solib_unloaded (struct so_list *solib)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *uiout = interp_ui_out (top_level_interpreter ());
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct ui_out *uiout;
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel, "library-unloaded");
> +      if (mi == NULL)
> +	continue;
>  
> -  ui_out_redirect (uiout, mi->event_channel);
> +      uiout = interp_ui_out (top_level_interpreter ());
>  
> -  ui_out_field_string (uiout, "id", solib->so_original_name);
> -  ui_out_field_string (uiout, "target-name", solib->so_original_name);
> -  ui_out_field_string (uiout, "host-name", solib->so_name);
> -  if (!gdbarch_has_global_solist (target_gdbarch ()))
> -    {
> -      ui_out_field_fmt (uiout, "thread-group", "i%d",
> -			current_inferior ()->num);
> -    }
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  ui_out_redirect (uiout, NULL);
> +      fprintf_unfiltered (mi->event_channel, "library-unloaded");
>  
> -  gdb_flush (mi->event_channel);
> +      ui_out_redirect (uiout, mi->event_channel);
>  
> -  do_cleanups (old_chain);
> +      ui_out_field_string (uiout, "id", solib->so_original_name);
> +      ui_out_field_string (uiout, "target-name", solib->so_original_name);
> +      ui_out_field_string (uiout, "host-name", solib->so_name);
> +      if (!gdbarch_has_global_solist (target_gdbarch ()))
> +	{
> +	  ui_out_field_fmt (uiout, "thread-group", "i%d",
> +			    current_inferior ()->num);
> +	}
> +
> +      ui_out_redirect (uiout, NULL);
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification about the command parameter change.  */
> @@ -1071,29 +1248,38 @@ mi_solib_unloaded (struct so_list *solib)
>  static void
>  mi_command_param_changed (const char *param, const char *value)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (mi_suppress_notification.cmd_param_changed)
>      return;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct ui_out *mi_uiout;
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,
> -		      "cmd-param-changed");
> +      if (mi == NULL)
> +	continue;
>  
> -  ui_out_redirect (mi_uiout, mi->event_channel);
> +      mi_uiout = interp_ui_out (top_level_interpreter ());
>  
> -  ui_out_field_string (mi_uiout, "param", param);
> -  ui_out_field_string (mi_uiout, "value", value);
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  ui_out_redirect (mi_uiout, NULL);
> +      fprintf_unfiltered (mi->event_channel, "cmd-param-changed");
>  
> -  gdb_flush (mi->event_channel);
> +      ui_out_redirect (mi_uiout, mi->event_channel);
>  
> -  do_cleanups (old_chain);
> +      ui_out_field_string (mi_uiout, "param", param);
> +      ui_out_field_string (mi_uiout, "value", value);
> +
> +      ui_out_redirect (mi_uiout, NULL);
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  /* Emit notification about the target memory change.  */
> @@ -1102,49 +1288,58 @@ static void
>  mi_memory_changed (struct inferior *inferior, CORE_ADDR memaddr,
>  		   ssize_t len, const bfd_byte *myaddr)
>  {
> -  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
> -  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
> -  struct obj_section *sec;
> -  struct cleanup *old_chain;
> +  struct switch_thru_all_uis state;
>  
>    if (mi_suppress_notification.memory)
>      return;
>  
> -  old_chain = make_cleanup_restore_target_terminal ();
> -  target_terminal_ours_for_output ();
> +  SWITCH_THRU_ALL_UIS (state)
> +    {
> +      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
> +      struct ui_out *mi_uiout;
> +      struct obj_section *sec;
> +      struct cleanup *old_chain;
>  
> -  fprintf_unfiltered (mi->event_channel,
> -		      "memory-changed");
> +      if (mi == NULL)
> +	continue;
>  
> -  ui_out_redirect (mi_uiout, mi->event_channel);
> +      mi_uiout = interp_ui_out (top_level_interpreter ());
>  
> -  ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num);
> -  ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr);
> -  ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len));
> +      old_chain = make_cleanup_restore_target_terminal ();
> +      target_terminal_ours_for_output ();
>  
> -  /* Append 'type=code' into notification if MEMADDR falls in the range of
> -     sections contain code.  */
> -  sec = find_pc_section (memaddr);
> -  if (sec != NULL && sec->objfile != NULL)
> -    {
> -      flagword flags = bfd_get_section_flags (sec->objfile->obfd,
> -					      sec->the_bfd_section);
> +      fprintf_unfiltered (mi->event_channel, "memory-changed");
>  
> -      if (flags & SEC_CODE)
> -	ui_out_field_string (mi_uiout, "type", "code");
> -    }
> +      ui_out_redirect (mi_uiout, mi->event_channel);
>  
> -  ui_out_redirect (mi_uiout, NULL);
> +      ui_out_field_fmt (mi_uiout, "thread-group", "i%d", inferior->num);
> +      ui_out_field_core_addr (mi_uiout, "addr", target_gdbarch (), memaddr);
> +      ui_out_field_fmt (mi_uiout, "len", "%s", hex_string (len));
>  
> -  gdb_flush (mi->event_channel);
> +      /* Append 'type=code' into notification if MEMADDR falls in the range of
> +	 sections contain code.  */
> +      sec = find_pc_section (memaddr);
> +      if (sec != NULL && sec->objfile != NULL)
> +	{
> +	  flagword flags = bfd_get_section_flags (sec->objfile->obfd,
> +						  sec->the_bfd_section);
>  
> -  do_cleanups (old_chain);
> +	  if (flags & SEC_CODE)
> +	    ui_out_field_string (mi_uiout, "type", "code");
> +	}
> +
> +      ui_out_redirect (mi_uiout, NULL);
> +
> +      gdb_flush (mi->event_channel);
> +
> +      do_cleanups (old_chain);
> +    }
>  }
>  
>  static int
>  report_initial_inferior (struct inferior *inf, void *closure)
>  {
> -  /* This function is called from mi_intepreter_init, and since
> +  /* This function is called from mi_interpreter_init, and since
>       mi_inferior_added assumes that inferior is fully initialized
>       and top_level_interpreter_data is set, we cannot call
>       it here.  */
> @@ -1250,4 +1445,32 @@ _initialize_mi_interp (void)
>    interp_factory_register (INTERP_MI2, mi_interp_factory);
>    interp_factory_register (INTERP_MI3, mi_interp_factory);
>    interp_factory_register (INTERP_MI, mi_interp_factory);
> +
> +  observer_attach_signal_received (mi_on_signal_received);
> +  observer_attach_end_stepping_range (mi_on_end_stepping_range);
> +  observer_attach_signal_exited (mi_on_signal_exited);
> +  observer_attach_exited (mi_on_exited);
> +  observer_attach_no_history (mi_on_no_history);
> +  observer_attach_new_thread (mi_new_thread);
> +  observer_attach_thread_exit (mi_thread_exit);
> +  observer_attach_inferior_added (mi_inferior_added);
> +  observer_attach_inferior_appeared (mi_inferior_appeared);
> +  observer_attach_inferior_exit (mi_inferior_exit);
> +  observer_attach_inferior_removed (mi_inferior_removed);
> +  observer_attach_record_changed (mi_record_changed);
> +  observer_attach_normal_stop (mi_on_normal_stop);
> +  observer_attach_target_resumed (mi_on_resume);
> +  observer_attach_solib_loaded (mi_solib_loaded);
> +  observer_attach_solib_unloaded (mi_solib_unloaded);
> +  observer_attach_about_to_proceed (mi_about_to_proceed);
> +  observer_attach_traceframe_changed (mi_traceframe_changed);
> +  observer_attach_tsv_created (mi_tsv_created);
> +  observer_attach_tsv_deleted (mi_tsv_deleted);
> +  observer_attach_tsv_modified (mi_tsv_modified);
> +  observer_attach_breakpoint_created (mi_breakpoint_created);
> +  observer_attach_breakpoint_deleted (mi_breakpoint_deleted);
> +  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);
>  }
> diff --git a/gdb/top.h b/gdb/top.h
> index f18b79e..805022f 100644
> --- a/gdb/top.h
> +++ b/gdb/top.h
> @@ -36,6 +36,9 @@ struct tl_interp_info;
>  
>  struct ui
>  {
> +  /* Pointer to next in singly-linked list.  */
> +  struct ui *next;
> +
>    /* The UI's command line buffer.  This is to used to accumulate
>       input until we have a whole command line.  */
>    struct buffer line_buffer;
> @@ -83,8 +86,34 @@ struct ui
>    struct ui_file *m_gdb_stdlog;
>  };
>  
> +/* The current UI.  */
>  extern struct ui *current_ui;
>  
> +/* The list of all UIs.  */
> +extern struct ui *ui_list;
> +
> +/* State for SWITCH_THRU_ALL_UIS.  Declared here because it is meant
> +   to be created on the stack, but should be treated as opaque.  */
> +struct switch_thru_all_uis
> +{
> +  struct ui *iter;
> +  struct cleanup *old_chain;
> +};
> +
> +/* Functions to drive SWITCH_THRU_ALL_UIS.  Though declared here by
> +   necessity, these functions should not be used other than via the
> +   SWITCH_THRU_ALL_UIS macro defined below.  */
> +extern void switch_thru_all_uis_init (struct switch_thru_all_uis *state);
> +extern int switch_thru_all_uis_cond (struct switch_thru_all_uis *state);
> +extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
> +
> +  /* Traverse through all UI, and switch the current UI to the one
> +     being iterated.  */
> +#define SWITCH_THRU_ALL_UIS(STATE)		\
> +  for (switch_thru_all_uis_init (&STATE);		\
> +       switch_thru_all_uis_cond (&STATE);		\
> +       switch_thru_all_uis_next (&STATE))		\

The last backslash is not necessary I think.

I was wondering why you did not name this "ALL_UIS", using the same pattern
as ALL_INFERIORS & al, but then I realized it's because this one actually
sets current_ui before each iteration (and restores it at the end).

I guess the reason you need to do this is because, again, everything relies on
accessing the global current_ui, whereas it should be passed down as a parameter.
I am not saying it should be done in this series (it's a big task in itself), but
we can probably tackle it after.  They way you did things should make it easy to
improve things later on.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 08/34] Always run async signal handlers in the main UI
  2016-05-06 12:43 ` [PATCH v3 08/34] Always run async signal handlers in the main UI Pedro Alves
@ 2016-05-19 19:28   ` Simon Marchi
  2016-05-26 18:13     ` Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-05-19 19:28 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-06 08:34 AM, Pedro Alves wrote:
> Async signal handlers have no connection to whichever was the current
> UI, and thus always run on the main one.
> 
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* event-loop.c: Include top.h.
> 	(invoke_async_signal_handlers): Switch to the main UI.
> 	* event-top.c (main_ui_): Update comment.
> 	(main_ui): New global.
> 	* top.h (main_ui): Declare.
> ---
>  gdb/event-loop.c | 4 ++++
>  gdb/event-top.c  | 5 ++---
>  gdb/top.h        | 5 +++++
>  3 files changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/gdb/event-loop.c b/gdb/event-loop.c
> index 60ef2a5..fe28305 100644
> --- a/gdb/event-loop.c
> +++ b/gdb/event-loop.c
> @@ -35,6 +35,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.  */
> @@ -967,6 +968,9 @@ invoke_async_signal_handlers (void)
>  	break;
>        any_ready = 1;
>        async_handler_ptr->ready = 0;
> +      /* Async signal handlers have no connection to whichever was the
> +	 current UI, and thus always run on the main one.  */
> +      current_ui = main_ui;
>        (*async_handler_ptr->proc) (async_handler_ptr->client_data);
>      }
>  
> diff --git a/gdb/event-top.c b/gdb/event-top.c
> index c6e3b7e..63f6896 100644
> --- a/gdb/event-top.c
> +++ b/gdb/event-top.c
> @@ -437,11 +437,10 @@ top_level_prompt (void)
>    return xstrdup (prompt);
>  }
>  
> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
> -   It always exists and is created automatically when GDB starts
> -   up.  */
> +/* The main UI.  */
>  static struct ui main_ui_;
>  
> +struct ui *main_ui = &main_ui_;

I'd suggest making the pointer const, to show (and make sure) that the main ui
never changes throughout the lifetime of the gdb instance:

  +struct ui * const main_ui = &main_ui_;

>  struct ui *current_ui = &main_ui_;
>  struct ui *ui_list = &main_ui_;

ui_list could be const for the same reason, while we're at it.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels
  2016-05-06 13:04   ` Eli Zaretskii
@ 2016-05-26 11:11     ` Pedro Alves
  2016-06-17 17:24       ` Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 11:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 05/06/2016 02:04 PM, Eli Zaretskii wrote:
>> From: Pedro Alves <palves@redhat.com>
>> Date: Fri,  6 May 2016 13:35:00 +0100
>>
>> +Although you may only choose a single interpreter at startup, it is
>> +possible to run an independent interpreter on a separate channel.
> 
> "Channel"?  What's that?  Can we find a better word?
> 
> No other comments to the doc part.  Thanks.

Thanks Eli.  Here's an attempt at clarifying things, using
the same terminology already used in other related commands.

From b58b402641e5cb5d0cbdf3bc2a815ada244be4c5 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 5 May 2016 13:06:03 +0100
Subject: [PATCH 30/34] [DOC] Document support for running interpreters on
 separate UIs

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* NEWS: Mention support for running interpreters on separate
	UIs and the new new-ui command.

gdb/doc/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.texinfo (Interpreters): Update intepreter-exec section,
	document new-ui and explain use case.
---
 gdb/doc/gdb.texinfo | 56 +++++++++++++++++++++++++++++++++++++++++++----------
 gdb/NEWS            | 18 +++++++++++++++++
 2 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f74c41c..a302d6e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24805,18 +24805,11 @@ The @sc{gdb/mi} interface included in @value{GDBN} 5.1, 5.2, and 5.3.
 @end table
 
 @cindex invoke another interpreter
-The interpreter being used by @value{GDBN} may not be dynamically
-switched at runtime.  Although possible, this could lead to a very
-precarious situation.  Consider an IDE using @sc{gdb/mi}.  If a user
-enters the command "interpreter-set console" in a console view,
-@value{GDBN} would switch to using the console interpreter, rendering
-the IDE inoperable!
 
 @kindex interpreter-exec
-Although you may only choose a single interpreter at startup, you may execute
-commands in any interpreter from the current interpreter using the appropriate
-command.  If you are running the console interpreter, simply use the
-@code{interpreter-exec} command:
+You may execute commands in any interpreter from the current
+interpreter using the appropriate command.  If you are running the
+console interpreter, simply use the @code{interpreter-exec} command:
 
 @smallexample
 interpreter-exec mi "-data-list-register-names"
@@ -24825,6 +24818,49 @@ interpreter-exec mi "-data-list-register-names"
 @sc{gdb/mi} has a similar command, although it is only available in versions of
 @value{GDBN} which support @sc{gdb/mi} version 2 (or greater).
 
+Note that @code{interpreter-exec} only changes the interpreter for the
+duration of the specified command.  It does not change the interpreter
+permanently.
+
+@cindex start a new independent interpreter
+
+Although you may only choose a single interpreter at startup, it is
+possible to run an independent interpreter on a specified input/output
+device (usually a tty).
+
+For example, consider a debugger GUI or IDE that wants to provide a
+@value{GDBN} console view.  It may do so by embedding a terminal
+emulator widget in its GUI, starting @value{GDBN} in the traditional
+command-line mode with stdin/stdout/stderr redirected to that
+terminal, and then creating an MI interpreter running on a specified
+input/output device.  The console interpreter created by @value{GDBN}
+at startup handles commands the user types in the terminal widget,
+while the GUI controls and synchronizes state with @value{GDBN} using
+the separate MI interpreter.
+
+To start a new secondary @dfn{user interface} running MI, use the
+@code{new-ui} command:
+
+@kindex new-ui
+@cindex new user interface
+@smallexample
+new-ui @var{interpreter} @var{tty}
+@end smallexample
+
+The @var{interpreter} parameter specifies the interpreter to run.
+This accepts the same values as the @code{interpreter-exec} command.
+For example, @samp{console}, @samp{mi}, @samp{mi2}, etc.  The
+@var{tty} parameter specifies the name of the bidirectional file the
+interpreter uses for input/output, usually the name of a
+pseudoterminal slave on Unix systems.  For example:
+
+@smallexample
+(@value{GDBP}) new-ui mi /dev/pts/9
+@end smallexample
+
+@noindent
+runs an MI interpreter on @file{/dev/pts/9}.
+
 @node TUI
 @chapter @value{GDBN} Text User Interface
 @cindex TUI
diff --git a/gdb/NEWS b/gdb/NEWS
index 7bf1e1a..c6ed63d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,20 @@
    Bounds: [lower = 0x7fffffffc390, upper = 0x7fffffffc3a3]
    0x0000000000400d7c in upper () at i386-mpx-sigsegv.c:68
 
+* Support for running interpreters on specified input/output devices
+
+  GDB now supports a new mechanism that allows frontends to provide
+  fully featured GDB console views, as a better alternative to
+  building such views on top of the "-interpreter-exec console"
+  command.  See the new "new-ui" command below.  With that command,
+  frontends can now start GDB in the traditional command-line mode
+  running in an embedded terminal emulator widget, and create a
+  separate MI interpreter running on a specified i/o device.  In this
+  way, GDB handles line editing, history, tab completion, etc. in the
+  console all by itself, and the GUI uses the separate MI interpreter
+  for its own control and synchronization, invisible to the command
+  line.
+
 * New commands
 
 skip -file file
@@ -40,6 +54,10 @@ skip -rfunction regular-expression
 maint info line-table REGEXP
   Display the contents of GDB's internal line table data struture.
 
+new-ui INTERP TTY
+  Start a new user interface instance running INTERP as interpreter,
+  using the TTY file for input/output.
+
 * Support for tracepoints and fast tracepoints on s390-linux and s390x-linux
   was added in GDBserver, including JIT compiling fast tracepoint's
   conditional expression bytecode into native code.
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 06/34] Introduce interpreter factories
  2016-05-18 19:20   ` Simon Marchi
@ 2016-05-26 18:08     ` Pedro Alves
  0 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:08 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 05/18/2016 08:19 PM, Simon Marchi wrote:
> On 16-05-06 08:34 AM, Pedro Alves wrote:

>> diff --git a/gdb/interps.h b/gdb/interps.h
>> index f0badc5..3065fdf 100644
>> --- a/gdb/interps.h
>> +++ b/gdb/interps.h
>> @@ -24,6 +24,17 @@
>>  
>>  struct ui_out;
>>  struct interp;
>> +struct ui;
>> +
>> +typedef struct interp *(*interp_factory_func) (const char *interp,
> 
> Nit:
> 
> In the functions of this type ({cli,mi,tui}_interp_factory), this parameter is named
> "name", so you could as well name it "name" here as well.

I've done that now.

> 
>> +					       struct ui *ui);
> 
> Even in the final result (with all patches applied), none of the factories
> use the ui parameter, is it expected?

I think that at some point I thought of storing a pointer to the UI in
the interp, but then ended up not needing it.  I've removed that
parameter now.

I'll post a patch in response to your other email.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 05/34] Make the interpreters be per UI
  2016-05-18 17:51   ` Simon Marchi
@ 2016-05-26 18:08     ` Pedro Alves
  0 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:08 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 05/18/2016 06:50 PM, Simon Marchi wrote:
> On 16-05-06 08:34 AM, Pedro Alves wrote:
>> 	(interp_exec, interpreter_exec_cmd, interpreter_completer)
>> 	(top_level_interpretertop_level_interpreter)
> 
> Two pastes here.

Fixed, thanks.

> 
>> diff --git a/gdb/interps.c b/gdb/interps.c
>> index b188d08..7f57132 100644
>> --- a/gdb/interps.c
>> +++ b/gdb/interps.c
>> @@ -39,11 +39,31 @@
>>  #include "top.h"		/* For command_loop.  */
>>  #include "continuations.h"
>>  
>> -/* True if the current interpreter in is async mode.  See interps.h
>> -   for more details.  This starts out disabled, until all the explicit
>> -   command line arguments (e.g., `gdb -ex "start" -ex "next"') are
>> -   processed.  */
>> -int interpreter_async = 0;
>> +/* Each UI has its own independent set of interpreters.  */
>> +
>> +struct ui_interp_info
>> +{
>> +  /* Each top level has its own independent set of interpreters.  */
>> +  struct interp *interp_list;
>> +  struct interp *current_interpreter;
>> +  struct interp *top_level_interpreter_ptr;
> 
> Could this be renamed top_level_interpreter?  I guess it was named _ptr to avoid clash in the global namespace.
> 

Good idea.  Here's the updated patch.

From 434ba98c49f0ab27416e4a0bb75d8295f97995c1 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Mon, 18 Apr 2016 19:27:02 +0100
Subject: [PATCH] Make the interpreters be per UI

Make each UI have its own interpreter list, top level interpreter,
current interpreter, etc.  The "interpreter_async" global is not
really specific to an struct interp (it crosses interpreter-exec ...),
so I moved it to "struct ui" directly, while the other globals were
left hidden in interps.c, opaque to the rest of GDB.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* breakpoint.c (bpstat_do_actions_1): Access the current UI's
	async field instead of the interpreter_async global.
	* cli/cli-script.c (execute_user_command, while_command)
	(if_command, script_from_file): Likewise.
	* compile/compile.c: Include top.h instead of interps.h.
	(compile_file_command, compile_code_command)
	(compile_print_command): Access the current UI's async field
	instead of the interpreter_async global.
	* guile/guile.c: Include top.h instead of interps.h.
	(guile_repl_command, guile_command, gdbscm_execute_gdb_command):
	Access the current UI's async field instead of the
	interpreter_async global.
	* guile/scm-ports.c: Include top.h instead of interps.h.
	(ioscm_with_output_to_port_worker): Access the current UI's async
	field instead of the interpreter_async global.
	* inf-loop.c (inferior_event_handler): Likewise.
	* infcall.c (run_inferior_call): Likewise.
	* infrun.c (reinstall_readline_callback_handler_cleanup)
	(fetch_inferior_event): Likewise.
	* interps.c (interpreter_async): Delete.
	(struct ui_interp_info): New.
	(get_current_interp_info): New function.
	(interp_list, current_interpreter, top_level_interpreter_ptr):
	Delete.
	(interp_add, interp_set, interp_lookup, interp_ui_out)
	(current_interp_set_logging, interp_set_temp)
	(current_interp_named_p): Adjust to per-UI interpreters.
	(command_interpreter): Delete.
	(command_interp, current_interp_command_loop, interp_quiet_p)
	(interp_exec, interpreter_exec_cmd, interpreter_completer)
	(top_level_interpreter, top_level_interpreter_data): Adjust to
	per-UI interpreters.
	* interps.h (interpreter_async): Delete.
	* main.c (captured_command_loop): Access the current UI's async
	field instead of the interpreter_async global.
	* python/python.c (python_interactive_command, python_command)
	(execute_gdb_command): Likewise.
	* top.c (maybe_wait_sync_command_done, execute_command_to_string):
	Access the current UI's async field instead of the
	interpreter_async global.
	* top.h (struct tl_interp_info): Forward declare.
	(struct ui) <interp_info, async>: New fields.
---
 gdb/breakpoint.c      |   2 +-
 gdb/cli/cli-script.c  |  16 +++---
 gdb/compile/compile.c |  14 ++---
 gdb/guile/guile.c     |  14 ++---
 gdb/guile/scm-ports.c |   6 +-
 gdb/inf-loop.c        |   2 +-
 gdb/infcall.c         |   6 +-
 gdb/infrun.c          |   4 +-
 gdb/interps.c         | 151 +++++++++++++++++++++++++++++++-------------------
 gdb/interps.h         |   9 ---
 gdb/main.c            |   2 +-
 gdb/python/python.c   |  12 ++--
 gdb/top.c             |   6 +-
 gdb/top.h             |  15 +++++
 14 files changed, 152 insertions(+), 107 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a39a15c..a28e956 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4733,7 +4733,7 @@ bpstat_do_actions_1 (bpstat *bsp)
 
       if (breakpoint_proceeded)
 	{
-	  if (interpreter_async)
+	  if (current_ui->async)
 	    /* If we are in async mode, then the target might be still
 	       running, not stopped at any breakpoint, so nothing for
 	       us to do here -- just return to the event loop.  */
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 7302330..5fc01b3 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -379,8 +379,8 @@ execute_user_command (struct cmd_list_element *c, char *args)
      not confused with Insight.  */
   in_user_command = 1;
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   command_nest_depth++;
   while (cmdlines)
@@ -661,8 +661,8 @@ while_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
-  old_chain = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  old_chain = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   execute_control_command_untraced (command);
   free_command_lines (&command);
@@ -685,8 +685,8 @@ if_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
-  old_chain = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  old_chain = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   execute_control_command_untraced (command);
   free_command_lines (&command);
@@ -1688,8 +1688,8 @@ script_from_file (FILE *stream, const char *file)
   source_line_number = 0;
   source_file_name = file;
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   {
 
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 77b4137..0c4a738 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -18,7 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "interps.h"
+#include "top.h"
 #include "ui-out.h"
 #include "command.h"
 #include "cli/cli-script.h"
@@ -91,8 +91,8 @@ compile_file_command (char *arg, int from_tty)
   char *buffer;
   struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   /* Check the user did not just <enter> after command.  */
   if (arg == NULL)
@@ -133,8 +133,8 @@ compile_code_command (char *arg, int from_tty)
   struct cleanup *cleanup;
   enum compile_i_scope_types scope = COMPILE_I_SIMPLE_SCOPE;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   if (arg != NULL && check_raw_argument (&arg))
     {
@@ -187,8 +187,8 @@ compile_print_command (char *arg_param, int from_tty)
   enum compile_i_scope_types scope = COMPILE_I_PRINT_ADDRESS_SCOPE;
   struct format_data fmt;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   /* Passing &FMT as SCOPE_DATA is safe as do_module_cleanup will not
      touch the stale pointer if compile_object_run has already quit.  */
diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c
index b010e59..117561d 100644
--- a/gdb/guile/guile.c
+++ b/gdb/guile/guile.c
@@ -27,7 +27,7 @@
 #include "cli/cli-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
-#include "interps.h"
+#include "top.h"
 #include "extension-priv.h"
 #include "utils.h"
 #include "version.h"
@@ -165,8 +165,8 @@ guile_repl_command (char *arg, int from_tty)
 {
   struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
 
@@ -198,8 +198,8 @@ guile_command (char *arg, int from_tty)
 {
   struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
 
@@ -328,8 +328,8 @@ gdbscm_execute_gdb_command (SCM command_scm, SCM rest)
     {
       struct cleanup *inner_cleanups;
 
-      inner_cleanups = make_cleanup_restore_integer (&interpreter_async);
-      interpreter_async = 0;
+      inner_cleanups = make_cleanup_restore_integer (&current_ui->async);
+      current_ui->async = 0;
 
       prevent_dont_repeat ();
       if (to_string)
diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
index b0f576e..5559475 100644
--- a/gdb/guile/scm-ports.c
+++ b/gdb/guile/scm-ports.c
@@ -23,7 +23,7 @@
 
 #include "defs.h"
 #include "gdb_select.h"
-#include "interps.h"
+#include "top.h"
 #include "target.h"
 #include "guile-internal.h"
 
@@ -517,8 +517,8 @@ ioscm_with_output_to_port_worker (SCM port, SCM thunk, enum oport oport,
 
   cleanups = set_batch_flag_and_make_cleanup_restore_page_info ();
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   port_file = ioscm_file_port_new (port);
 
diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c
index 2591ae9..d006df8 100644
--- a/gdb/inf-loop.c
+++ b/gdb/inf-loop.c
@@ -61,7 +61,7 @@ inferior_event_handler (enum inferior_event_type event_type,
 
       /* When running a command list (from a user command, say), these
 	 are only run when the command list is all done.  */
-      if (interpreter_async)
+      if (current_ui->async)
 	{
 	  check_frame_language_change ();
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 77cd931..11f5aba 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -560,13 +560,13 @@ run_inferior_call (struct call_thread_fsm *sm,
   ptid_t call_thread_ptid = call_thread->ptid;
   int saved_sync_execution = sync_execution;
   int was_running = call_thread->state == THREAD_RUNNING;
-  int saved_interpreter_async = interpreter_async;
+  int saved_ui_async = current_ui->async;
 
   /* Infcalls run synchronously, in the foreground.  */
   sync_execution = 1;
   /* So that we don't print the prompt prematurely in
      fetch_inferior_event.  */
-  interpreter_async = 0;
+  current_ui->async = 0;
 
   call_thread->control.in_infcall = 1;
 
@@ -601,7 +601,7 @@ run_inferior_call (struct call_thread_fsm *sm,
      again here.  In other cases, stdin will be re-enabled by
      inferior_event_handler, when an exception is thrown.  */
   sync_execution = saved_sync_execution;
-  interpreter_async = saved_interpreter_async;
+  current_ui->async = saved_ui_async;
 
   /* At this point the current thread may have changed.  Refresh
      CALL_THREAD as it could be invalid if its thread has exited.  */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index cfb1d06..ba7144a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3806,7 +3806,7 @@ wait_for_inferior (void)
 static void
 reinstall_readline_callback_handler_cleanup (void *arg)
 {
-  if (!interpreter_async)
+  if (!current_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,
@@ -3993,7 +3993,7 @@ fetch_inferior_event (void *client_data)
   /* 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 (interpreter_async && was_sync && !sync_execution)
+  if (current_ui->async && was_sync && !sync_execution)
     observer_notify_sync_execution_done ();
 
   if (cmd_done
diff --git a/gdb/interps.c b/gdb/interps.c
index b188d08..f19db54 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -39,11 +39,31 @@
 #include "top.h"		/* For command_loop.  */
 #include "continuations.h"
 
-/* True if the current interpreter in is async mode.  See interps.h
-   for more details.  This starts out disabled, until all the explicit
-   command line arguments (e.g., `gdb -ex "start" -ex "next"') are
-   processed.  */
-int interpreter_async = 0;
+/* Each UI has its own independent set of interpreters.  */
+
+struct ui_interp_info
+{
+  /* Each top level has its own independent set of interpreters.  */
+  struct interp *interp_list;
+  struct interp *current_interpreter;
+  struct interp *top_level_interpreter;
+
+  /* The interpreter that is active while `interp_exec' is active, NULL
+     at all other times.  */
+  struct interp *command_interpreter;
+};
+
+/* Get the current UI's ui_interp_info object.  Never returns NULL.  */
+
+static struct ui_interp_info *
+get_current_interp_info (void)
+{
+  struct ui *ui = current_ui;
+
+  if (ui->interp_info == NULL)
+    ui->interp_info = XCNEW (struct ui_interp_info);
+  return ui->interp_info;
+}
 
 struct interp
 {
@@ -71,12 +91,6 @@ struct interp
 
 void _initialize_interpreter (void);
 
-/* Variables local to this file: */
-
-static struct interp *interp_list = NULL;
-static struct interp *current_interpreter = NULL;
-static struct interp *top_level_interpreter_ptr = NULL;
-
 /* interp_new - This allocates space for a new interpreter,
    fills the fields from the inputs, and returns a pointer to the
    interpreter.  */
@@ -104,10 +118,12 @@ interp_new (const char *name, const struct interp_procs *procs)
 void
 interp_add (struct interp *interp)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
   gdb_assert (interp_lookup (interp->name) == NULL);
 
-  interp->next = interp_list;
-  interp_list = interp;
+  interp->next = ui_interp->interp_list;
+  ui_interp->interp_list = interp;
 }
 
 /* This sets the current interpreter to be INTERP.  If INTERP has not
@@ -127,24 +143,24 @@ interp_add (struct interp *interp)
 int
 interp_set (struct interp *interp, int top_level)
 {
-  struct interp *old_interp = current_interpreter;
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *old_interp = ui_interp->current_interpreter;
   int first_time = 0;
   char buffer[64];
 
   /* If we already have an interpreter, then trying to
      set top level interpreter is kinda pointless.  */
-  gdb_assert (!top_level || !current_interpreter);
-  gdb_assert (!top_level || !top_level_interpreter_ptr);
+  gdb_assert (!top_level || !ui_interp->current_interpreter);
+  gdb_assert (!top_level || !ui_interp->top_level_interpreter);
 
-  if (current_interpreter != NULL)
+  if (old_interp != NULL)
     {
       ui_out_flush (current_uiout);
-      if (current_interpreter->procs->suspend_proc
-	  && !current_interpreter->procs->suspend_proc (current_interpreter->
-							data))
+      if (old_interp->procs->suspend_proc
+	  && !old_interp->procs->suspend_proc (old_interp->data))
 	{
 	  error (_("Could not suspend interpreter \"%s\"."),
-		 current_interpreter->name);
+		 old_interp->name);
 	}
     }
   else
@@ -152,18 +168,18 @@ interp_set (struct interp *interp, int top_level)
       first_time = 1;
     }
 
-  current_interpreter = interp;
+  ui_interp->current_interpreter = interp;
   if (top_level)
-    top_level_interpreter_ptr = interp;
+    ui_interp->top_level_interpreter = interp;
 
   /* We use interpreter_p for the "set interpreter" variable, so we need
      to make sure we have a malloc'ed copy for the set command to free.  */
   if (interpreter_p != NULL
-      && strcmp (current_interpreter->name, interpreter_p) != 0)
+      && strcmp (interp->name, interpreter_p) != 0)
     {
       xfree (interpreter_p);
 
-      interpreter_p = xstrdup (current_interpreter->name);
+      interpreter_p = xstrdup (interp->name);
     }
 
   /* Run the init proc.  If it fails, try to restore the old interp.  */
@@ -209,12 +225,15 @@ interp_set (struct interp *interp, int top_level)
 struct interp *
 interp_lookup (const char *name)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *interp;
 
   if (name == NULL || strlen (name) == 0)
     return NULL;
 
-  for (interp = interp_list; interp != NULL; interp = interp->next)
+  for (interp = ui_interp->interp_list;
+       interp != NULL;
+       interp = interp->next)
     {
       if (strcmp (interp->name, name) == 0)
 	return interp;
@@ -228,34 +247,37 @@ interp_lookup (const char *name)
 struct ui_out *
 interp_ui_out (struct interp *interp)
 {
-  if (interp != NULL)
-    return interp->procs->ui_out_proc (interp);
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
 
-  return current_interpreter->procs->ui_out_proc (current_interpreter);
+  if (interp == NULL)
+    interp = ui_interp->current_interpreter;
+  return interp->procs->ui_out_proc (interp);
 }
 
 int
 current_interp_set_logging (int start_log, struct ui_file *out,
 			    struct ui_file *logfile)
 {
-  if (current_interpreter == NULL
-      || current_interpreter->procs->set_logging_proc == NULL)
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *interp = ui_interp->current_interpreter;
+
+  if (interp == NULL
+      || interp->procs->set_logging_proc == NULL)
     return 0;
 
-  return current_interpreter->procs->set_logging_proc (current_interpreter,
-						       start_log, out,
-						       logfile);
+  return interp->procs->set_logging_proc (interp, start_log, out, logfile);
 }
 
 /* Temporarily overrides the current interpreter.  */
 struct interp *
 interp_set_temp (const char *name)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *interp = interp_lookup (name);
-  struct interp *old_interp = current_interpreter;
+  struct interp *old_interp = ui_interp->current_interpreter;
 
   if (interp)
-    current_interpreter = interp;
+    ui_interp->current_interpreter = interp;
   return old_interp;
 }
 
@@ -279,16 +301,15 @@ interp_name (struct interp *interp)
 int
 current_interp_named_p (const char *interp_name)
 {
-  if (current_interpreter)
-    return (strcmp (current_interpreter->name, interp_name) == 0);
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *interp = ui_interp->current_interpreter;
+
+  if (interp != NULL)
+    return (strcmp (interp->name, interp_name) == 0);
 
   return 0;
 }
 
-/* The interpreter that is active while `interp_exec' is active, NULL
-   at all other times.  */
-static struct interp *command_interpreter;
-
 /* The interpreter that was active when a command was executed.
    Normally that'd always be CURRENT_INTERPRETER, except that MI's
    -interpreter-exec command doesn't actually flip the current
@@ -302,28 +323,35 @@ static struct interp *command_interpreter;
 struct interp *
 command_interp (void)
 {
-  if (command_interpreter != NULL)
-    return command_interpreter;
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
+  if (ui_interp->command_interpreter != NULL)
+    return ui_interp->command_interpreter;
   else
-    return current_interpreter;
+    return ui_interp->current_interpreter;
 }
 
 /* Run the current command interpreter's main loop.  */
 void
 current_interp_command_loop (void)
 {
-  gdb_assert (current_interpreter != NULL);
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp *interp = ui_interp->current_interpreter;
+
+  gdb_assert (ui_interp->current_interpreter != NULL);
 
-  current_interpreter->procs->command_loop_proc (current_interpreter->data);
+  interp->procs->command_loop_proc (interp->data);
 }
 
 int
 interp_quiet_p (struct interp *interp)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
   if (interp != NULL)
     return interp->quiet_p;
   else
-    return current_interpreter->quiet_p;
+    return ui_interp->current_interpreter->quiet_p;
 }
 
 static int
@@ -341,18 +369,20 @@ interp_set_quiet (struct interp *interp, int quiet)
 struct gdb_exception
 interp_exec (struct interp *interp, const char *command_str)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
   struct gdb_exception ex;
   struct interp *save_command_interp;
 
   gdb_assert (interp->procs->exec_proc != NULL);
 
   /* See `command_interp' for why we do this.  */
-  save_command_interp = command_interpreter;
-  command_interpreter = interp;
+  save_command_interp = ui_interp->command_interpreter;
+  ui_interp->command_interpreter = interp;
 
   ex = interp->procs->exec_proc (interp->data, command_str);
 
-  command_interpreter = save_command_interp;
+  ui_interp->command_interpreter = save_command_interp;
 
   return ex;
 }
@@ -379,6 +409,7 @@ clear_interpreter_hooks (void)
 static void
 interpreter_exec_cmd (char *args, int from_tty)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   struct interp *old_interp, *interp_to_use;
   char **prules = NULL;
   char **trule = NULL;
@@ -400,7 +431,7 @@ interpreter_exec_cmd (char *args, int from_tty)
   if (nrules < 2)
     error (_("usage: interpreter-exec <interpreter> [ <command> ... ]"));
 
-  old_interp = current_interpreter;
+  old_interp = ui_interp->current_interpreter;
 
   interp_to_use = interp_lookup (prules[0]);
   if (interp_to_use == NULL)
@@ -438,12 +469,15 @@ static VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
   int textlen;
   VEC (char_ptr) *matches = NULL;
   struct interp *interp;
 
   textlen = strlen (text);
-  for (interp = interp_list; interp != NULL; interp = interp->next)
+  for (interp = ui_interp->interp_list;
+       interp != NULL;
+       interp = interp->next)
     {
       if (strncmp (interp->name, text, textlen) == 0)
 	{
@@ -474,14 +508,19 @@ interpreter_completer (struct cmd_list_element *ignore,
 struct interp *
 top_level_interpreter (void)
 {
-  return top_level_interpreter_ptr;  
+  struct ui_interp_info *ui_interp = get_current_interp_info ();
+
+  return ui_interp->top_level_interpreter;
 }
 
 void *
 top_level_interpreter_data (void)
 {
-  gdb_assert (top_level_interpreter_ptr);
-  return top_level_interpreter_ptr->data;  
+  struct interp *interp;
+
+  interp = top_level_interpreter ();
+  gdb_assert (interp != NULL);
+  return interp->data;
 }
 
 /* This just adds the "interpreter-exec" command.  */
diff --git a/gdb/interps.h b/gdb/interps.h
index 19cd1c2..f0badc5 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -93,15 +93,6 @@ extern struct interp *top_level_interpreter (void);
 
 extern struct interp *command_interp (void);
 
-/* True if the current interpreter is in async mode, false if in sync
-   mode.  If in sync mode, running a synchronous execution command
-   (with execute_command, e.g, "next") will not return until the
-   command is finished.  If in async mode, then running a synchronous
-   command returns right after resuming the target.  Waiting for the
-   command's completion is later done on the top event loop (using
-   continuations).  */
-extern int interpreter_async;
-
 extern void clear_interpreter_hooks (void);
 
 /* well-known interpreters */
diff --git a/gdb/main.c b/gdb/main.c
index 03d6bbd..d84340e 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -311,7 +311,7 @@ captured_command_loop (void *data)
 {
   /* Top-level execution commands can be run in the background from
      here on.  */
-  interpreter_async = 1;
+  current_ui->async = 1;
 
   current_interp_command_loop ();
   /* FIXME: cagney/1999-11-05: A correct command_loop() implementaton
diff --git a/gdb/python/python.c b/gdb/python/python.c
index c706644..fa1c78e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -321,8 +321,8 @@ python_interactive_command (char *arg, int from_tty)
   struct cleanup *cleanup;
   int err;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  cleanup = make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
 
@@ -466,8 +466,8 @@ python_command (char *arg, int from_tty)
 
   cleanup = ensure_python_env (get_current_arch (), current_language);
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   arg = skip_spaces (arg);
   if (arg && *arg)
@@ -650,8 +650,8 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
       struct cleanup *cleanup = make_cleanup (xfree, copy);
       struct interp *interp;
 
-      make_cleanup_restore_integer (&interpreter_async);
-      interpreter_async = 0;
+      make_cleanup_restore_integer (&current_ui->async);
+      current_ui->async = 0;
 
       make_cleanup_restore_ui_out (&current_uiout);
       /* Use the console interpreter uiout to have the same print format
diff --git a/gdb/top.c b/gdb/top.c
index a34635b..3842f0c 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -407,7 +407,7 @@ 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 (!interpreter_async && !was_sync && sync_execution)
+  if (!current_ui->async && !was_sync && sync_execution)
     wait_sync_command_done ();
 }
 
@@ -525,8 +525,8 @@ execute_command_to_string (char *p, int from_tty)
      restoration callbacks.  */
   cleanup = set_batch_flag_and_make_cleanup_restore_page_info ();
 
-  make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  make_cleanup_restore_integer (&current_ui->async);
+  current_ui->async = 0;
 
   str_file = mem_fileopen ();
 
diff --git a/gdb/top.h b/gdb/top.h
index d404427..f18b79e 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -23,6 +23,8 @@
 #include "buffer.h"
 #include "event-loop.h"
 
+struct tl_interp_info;
+
 /* 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
@@ -50,6 +52,19 @@ struct ui
      processing.  */
   void (*input_handler) (char *);
 
+  /* Each UI has its own independent set of interpreters.  */
+  struct ui_interp_info *interp_info;
+
+  /* True if the UI is in async mode, false if in sync mode.  If in
+     sync mode, a synchronous execution command (e.g, "next") does not
+     return until the command is finished.  If in async mode, then
+     running a synchronous command returns right after resuming the
+     target.  Waiting for the command's completion is later done on
+     the top event loop.  For the main UI, this starts out disabled,
+     until all the explicit command line arguments (e.g., `gdb -ex
+     "start" -ex "next"') are processed.  */
+  int async;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 06/34] Introduce interpreter factories
  2016-05-18 19:18   ` Simon Marchi
@ 2016-05-26 18:11     ` Pedro Alves
  0 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:11 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 05/18/2016 08:18 PM, Simon Marchi wrote:
> On 16-05-06 08:34 AM, Pedro Alves wrote:
>> +/* See interps.h.  */
>> +
>> +struct interp *
>> +interp_lookup (const char *name)
>> +{
>> +  struct ui *ui = current_ui;
>> +  struct interp_factory *factory;
>> +  struct interp *interp;
>> +  int ix;
>> +
>> +  if (name == NULL || strlen (name) == 0)
>> +    return NULL;
>> +
>> +  /* Only create each interpreter once per top level.  */
>> +  interp = interp_lookup_existing (name);
>> +  if (interp != NULL)
>> +    return interp;
>> +
>> +  for (ix = 0;
>> +       VEC_iterate (interp_factory_p, interpreter_factories, ix, factory);
>> +       ++ix)
>> +    if (strcmp (factory->name, name) == 0)
>> +      {
>> +	interp = factory->func (name, ui);
>> +	interp_add (interp);
>> +	return interp;
>> +      }
>> +
>> +  return NULL;
>> +}
>> +
> 
> I think there are some opportunities to reduce the number of functions that directly
> access global state.  For example, I think it would be clearer if interp_lookup took
> a struct ui* as argument instead of accessing current_ui.  It would show that it's used
> to lookup an interpreter by name in a ui.  Similarly, it calls interp_lookup_existing and
> interp_add, which both use get_current_interp_info(), which is essentially accessing
> current_ui.  I believe it would be easier to follow if some caller provided the struct ui
> and it was passed down by parameters.

I've done that now.  See patch below.

I agree to a point for these functions in particular, but
I'm not entirely sold on this in general, because all callers
will necessarily need to pass down 'current_ui'.

If you need to do something to an interpreter of a non-current UI, it's
likely that you should be switching the current UI to that UI, first.
Not having a UI parameter means that you're forced to switch
the current UI, and thus get it right.

I don't think it'll ever be possible, or desirable even, to
eliminate the concept of a current UI, since that would mean
basically passing a UI down to _every_ function that might want to 
do output (fprintf_unfiltered, etc.), which basically means
everything.  It'd equivalent of wanting to pass down 
current_uiout and gdb_stdout, etc. as parameters everywhere.
It's just not going to happen.

Anyway, this particular case seems easy to change in either direction
at any time.  Here's the updated patch.

From ef7acb5ab8122c3465f45509020d5da4f352926f Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 26 May 2016 17:28:55 +0100
Subject: [PATCH] Introduce interpreter factories

If every UI instance has its own set of interpreters, then the current
scheme of creating the interpreters at GDB initialization time no
longer works.  We need to create them whenever a new UI instance is
created.

The scheme implemented here has each interpreter register a factory
callback that when called creates a new instance of a specific
interpreter type.  Then, when some code in gdb looks up an interpreter
(always by name), if there's none yet, the factory method is called to
construct one.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* cli/cli-interp.c (cli_uiout): Delete, moved into ...
	(struct cli_interp): ... this new structure.
	(cli_on_normal_stop, cli_on_signal_received)
	(cli_on_end_stepping_range, cli_on_signal_exited, cli_on_exited)
	(cli_on_no_history): Use interp_ui_out.
	(cli_interpreter_init): If top level, set the cli_interp global.
	(cli_interpreter_init): Return the interp's data instead of NULL.
	(cli_interpreter_resume, cli_interpreter_exec, cli_ui_out): Adjust
	to cli_uiout being in the interpreter's data.
	(cli_interp_procs): New, factored out from _initialize_cli_interp.
	(cli_interp_factory): New function.
	(_initialize_cli_interp): Call interp_factory_register.
	* interps.c (get_interp_info): New, factored out from ...
	(get_current_interp_info): ... this.
	(interp_new): Add parameter 'data'.  Store it.
	(struct interp_factory): New function.
	(interp_factory_p): New typedef.  Define a VEC_P.
	(interpreter_factories): New global.
	(interp_factory_register): New function.
	(interp_add): Add 'ui' parameter.  Use get_interp_info and
	interp_lookup_existing.
	(interp_lookup): Rename to ...
	(interp_lookup_existing): ... this.  Add 'ui' parameter.  Don't
	check for NULL or empty name here.
	(interp_lookup): Add 'ui' parameter and reimplement.
	(interp_set_temp, interpreter_exec_cmd): Adjust.
	(interpreter_completer): Complete on registered interpreter
	factories instead of interpreters.
	* interps.h (interp_factory_func): New typedef.
	(interp_factory_register): Declare.
	(interp_new, interp_add): Adjust.
	(interp_lookup): Declare.
	* main.c (captured_main): Adjust.
	* mi/mi-interp.c (mi_cmd_interpreter_exec): Adjust.
	(mi_interp_procs): New, factored out from
	_initialize_mi_interp.
	(mi_interp_factory): New function.
	* python/python.c (execute_gdb_command): Adjust.
	* tui/tui-interp.c (tui_init): If top level, set the tui_interp
	global.
	(tui_interp_procs): New.
	(tui_interp_factory): New function.
	(_initialize_tui_interp): Call interp_factory_register.
---
 gdb/cli/cli-interp.c |  87 +++++++++++++++++++++-------------
 gdb/interps.c        | 130 +++++++++++++++++++++++++++++++++++++++++----------
 gdb/interps.h        |  24 ++++++++--
 gdb/main.c           |   2 +-
 gdb/mi/mi-interp.c   |  42 ++++++++++-------
 gdb/python/python.c  |   2 +-
 gdb/tui/tui-interp.c |  38 +++++++++------
 7 files changed, 234 insertions(+), 91 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index dfbd808..8eae0ac 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -26,9 +26,14 @@
 #include "infrun.h"
 #include "observer.h"
 
-/* These are the ui_out and the interpreter for the console
-   interpreter.  */
-struct ui_out *cli_uiout;
+/* The console interpreter.  */
+struct cli_interp
+{
+  /* The ui_out for the console interpreter.  */
+  struct ui_out *cli_uiout;
+};
+
+/* The interpreter for the console interpreter.  */
 static struct interp *cli_interp;
 
 /* Longjmp-safe wrapper for "execute_command".  */
@@ -48,7 +53,7 @@ cli_on_normal_stop (struct bpstats *bs, int print_frame)
   if (!interp_quiet_p (cli_interp))
     {
       if (print_frame)
-	print_stop_event (cli_uiout);
+	print_stop_event (interp_ui_out (cli_interp));
     }
 }
 
@@ -58,7 +63,7 @@ static void
 cli_on_signal_received (enum gdb_signal siggnal)
 {
   if (!interp_quiet_p (cli_interp))
-    print_signal_received_reason (cli_uiout, siggnal);
+    print_signal_received_reason (interp_ui_out (cli_interp), siggnal);
 }
 
 /* Observer for the end_stepping_range notification.  */
@@ -67,7 +72,7 @@ static void
 cli_on_end_stepping_range (void)
 {
   if (!interp_quiet_p (cli_interp))
-    print_end_stepping_range_reason (cli_uiout);
+    print_end_stepping_range_reason (interp_ui_out (cli_interp));
 }
 
 /* Observer for the signalled notification.  */
@@ -76,7 +81,7 @@ static void
 cli_on_signal_exited (enum gdb_signal siggnal)
 {
   if (!interp_quiet_p (cli_interp))
-    print_signal_exited_reason (cli_uiout, siggnal);
+    print_signal_exited_reason (interp_ui_out (cli_interp), siggnal);
 }
 
 /* Observer for the exited notification.  */
@@ -85,7 +90,7 @@ static void
 cli_on_exited (int exitstatus)
 {
   if (!interp_quiet_p (cli_interp))
-    print_exited_reason (cli_uiout, exitstatus);
+    print_exited_reason (interp_ui_out (cli_interp), exitstatus);
 }
 
 /* Observer for the no_history notification.  */
@@ -94,7 +99,7 @@ static void
 cli_on_no_history (void)
 {
   if (!interp_quiet_p (cli_interp))
-    print_no_history_reason (cli_uiout);
+    print_no_history_reason (interp_ui_out (cli_interp));
 }
 
 /* Observer for the sync_execution_done notification.  */
@@ -120,6 +125,9 @@ cli_on_command_error (void)
 static void *
 cli_interpreter_init (struct interp *self, int top_level)
 {
+  if (top_level)
+    cli_interp = self;
+
   /* If changing this, remember to update tui-interp.c as well.  */
   observer_attach_normal_stop (cli_on_normal_stop);
   observer_attach_end_stepping_range (cli_on_end_stepping_range);
@@ -130,12 +138,13 @@ cli_interpreter_init (struct interp *self, int top_level)
   observer_attach_sync_execution_done (cli_on_sync_execution_done);
   observer_attach_command_error (cli_on_command_error);
 
-  return NULL;
+  return interp_data (self);
 }
 
 static int
 cli_interpreter_resume (void *data)
 {
+  struct cli_interp *cli = (struct cli_interp *) data;
   struct ui_file *stream;
 
   /*sync_execution = 1; */
@@ -144,17 +153,17 @@ cli_interpreter_resume (void *data)
      previously writing to gdb_stdout, then set it to the new
      gdb_stdout afterwards.  */
 
-  stream = cli_out_set_stream (cli_uiout, gdb_stdout);
+  stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout);
   if (stream != gdb_stdout)
     {
-      cli_out_set_stream (cli_uiout, stream);
+      cli_out_set_stream (cli->cli_uiout, stream);
       stream = NULL;
     }
 
   gdb_setup_readline ();
 
   if (stream != NULL)
-    cli_out_set_stream (cli_uiout, gdb_stdout);
+    cli_out_set_stream (cli->cli_uiout, gdb_stdout);
 
   return 1;
 }
@@ -169,6 +178,7 @@ cli_interpreter_suspend (void *data)
 static struct gdb_exception
 cli_interpreter_exec (void *data, const char *command_str)
 {
+  struct cli_interp *cli = (struct cli_interp *) data;
   struct ui_file *old_stream;
   struct gdb_exception result;
 
@@ -184,9 +194,9 @@ cli_interpreter_exec (void *data, const char *command_str)
 
      It is important that it gets reset everytime, since the user
      could set gdb to use a different interpreter.  */
-  old_stream = cli_out_set_stream (cli_uiout, gdb_stdout);
-  result = safe_execute_command (cli_uiout, str, 1);
-  cli_out_set_stream (cli_uiout, old_stream);
+  old_stream = cli_out_set_stream (cli->cli_uiout, gdb_stdout);
+  result = safe_execute_command (cli->cli_uiout, str, 1);
+  cli_out_set_stream (cli->cli_uiout, old_stream);
   return result;
 }
 
@@ -222,7 +232,34 @@ safe_execute_command (struct ui_out *command_uiout, char *command, int from_tty)
 static struct ui_out *
 cli_ui_out (struct interp *self)
 {
-  return cli_uiout;
+  struct cli_interp *cli = (struct cli_interp *) interp_data (self);
+
+  return cli->cli_uiout;
+}
+
+/* The CLI interpreter's vtable.  */
+
+static const struct interp_procs cli_interp_procs = {
+  cli_interpreter_init,		/* init_proc */
+  cli_interpreter_resume,	/* resume_proc */
+  cli_interpreter_suspend,	/* suspend_proc */
+  cli_interpreter_exec,		/* exec_proc */
+  cli_ui_out,			/* ui_out_proc */
+  NULL,                       	/* set_logging_proc */
+  cli_command_loop            	/* command_loop_proc */
+};
+
+/* Factory for CLI interpreters.  */
+
+static struct interp *
+cli_interp_factory (const char *name)
+{
+  struct cli_interp *cli = XNEW (struct cli_interp);
+
+  /* Create a default uiout builder for the CLI.  */
+  cli->cli_uiout = cli_out_new (gdb_stdout);
+
+  return interp_new (name, &cli_interp_procs, cli);
 }
 
 /* Standard gdb initialization hook.  */
@@ -231,19 +268,5 @@ extern initialize_file_ftype _initialize_cli_interp; /* -Wmissing-prototypes */
 void
 _initialize_cli_interp (void)
 {
-  static const struct interp_procs procs = {
-    cli_interpreter_init,	/* init_proc */
-    cli_interpreter_resume,	/* resume_proc */
-    cli_interpreter_suspend,	/* suspend_proc */
-    cli_interpreter_exec,	/* exec_proc */
-    cli_ui_out,			/* ui_out_proc */
-    NULL,                       /* set_logging_proc */
-    cli_command_loop            /* command_loop_proc */
-  };
-
-  /* Create a default uiout builder for the CLI.  */
-  cli_uiout = cli_out_new (gdb_stdout);
-  cli_interp = interp_new (INTERP_CONSOLE, &procs);
-
-  interp_add (cli_interp);
+  interp_factory_register (INTERP_CONSOLE, cli_interp_factory);
 }
diff --git a/gdb/interps.c b/gdb/interps.c
index f19db54..fd08de5 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -53,18 +53,25 @@ struct ui_interp_info
   struct interp *command_interpreter;
 };
 
-/* Get the current UI's ui_interp_info object.  Never returns NULL.  */
+/* Get UI's ui_interp_info object.  Never returns NULL.  */
 
 static struct ui_interp_info *
-get_current_interp_info (void)
+get_interp_info (struct ui *ui)
 {
-  struct ui *ui = current_ui;
-
   if (ui->interp_info == NULL)
     ui->interp_info = XCNEW (struct ui_interp_info);
   return ui->interp_info;
 }
 
+/* Get the current UI's ui_interp_info object.  Never returns
+   NULL.  */
+
+static struct ui_interp_info *
+get_current_interp_info (void)
+{
+  return get_interp_info (current_ui);
+}
+
 struct interp
 {
   /* This is the name in "-i=" and set interpreter.  */
@@ -91,18 +98,21 @@ struct interp
 
 void _initialize_interpreter (void);
 
+static struct interp *interp_lookup_existing (struct ui *ui,
+					      const char *name);
+
 /* interp_new - This allocates space for a new interpreter,
    fills the fields from the inputs, and returns a pointer to the
    interpreter.  */
 struct interp *
-interp_new (const char *name, const struct interp_procs *procs)
+interp_new (const char *name, const struct interp_procs *procs, void *data)
 {
   struct interp *new_interp;
 
   new_interp = XNEW (struct interp);
 
   new_interp->name = xstrdup (name);
-  new_interp->data = NULL;
+  new_interp->data = data;
   new_interp->quiet_p = 0;
   new_interp->procs = procs;
   new_interp->inited = 0;
@@ -113,14 +123,57 @@ interp_new (const char *name, const struct interp_procs *procs)
   return new_interp;
 }
 
+/* An interpreter factory.  Maps an interpreter name to the factory
+   function that instantiates an interpreter by that name.  */
+
+struct interp_factory
+{
+  /* This is the name in "-i=INTERP" and "interpreter-exec INTERP".  */
+  const char *name;
+
+  /* The function that creates the interpreter.  */
+  interp_factory_func func;
+};
+
+typedef struct interp_factory *interp_factory_p;
+DEF_VEC_P(interp_factory_p);
+
+/* The registered interpreter factories.  */
+static VEC(interp_factory_p) *interpreter_factories = NULL;
+
+/* See interps.h.  */
+
+void
+interp_factory_register (const char *name, interp_factory_func func)
+{
+  struct interp_factory *f;
+  int ix;
+
+  /* Assert that no factory for NAME is already registered.  */
+  for (ix = 0;
+       VEC_iterate (interp_factory_p, interpreter_factories, ix, f);
+       ++ix)
+    if (strcmp (f->name, name) == 0)
+      {
+	internal_error (__FILE__, __LINE__,
+			_("interpreter factory already registered: \"%s\"\n"),
+			name);
+      }
+
+  f = XNEW (struct interp_factory);
+  f->name = name;
+  f->func = func;
+  VEC_safe_push (interp_factory_p, interpreter_factories, f);
+}
+
 /* Add interpreter INTERP to the gdb interpreter list.  The
    interpreter must not have previously been added.  */
 void
-interp_add (struct interp *interp)
+interp_add (struct ui *ui, struct interp *interp)
 {
-  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct ui_interp_info *ui_interp = get_interp_info (ui);
 
-  gdb_assert (interp_lookup (interp->name) == NULL);
+  gdb_assert (interp_lookup_existing (ui, interp->name) == NULL);
 
   interp->next = ui_interp->interp_list;
   ui_interp->interp_list = interp;
@@ -219,18 +272,15 @@ interp_set (struct interp *interp, int top_level)
   return 1;
 }
 
-/* interp_lookup - Looks up the interpreter for NAME.  If no such
-   interpreter exists, return NULL, otherwise return a pointer to the
-   interpreter.  */
-struct interp *
-interp_lookup (const char *name)
+/* Look up the interpreter for NAME.  If no such interpreter exists,
+   return NULL, otherwise return a pointer to the interpreter.  */
+
+static struct interp *
+interp_lookup_existing (struct ui *ui, const char *name)
 {
-  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct ui_interp_info *ui_interp = get_interp_info (ui);
   struct interp *interp;
 
-  if (name == NULL || strlen (name) == 0)
-    return NULL;
-
   for (interp = ui_interp->interp_list;
        interp != NULL;
        interp = interp->next)
@@ -242,6 +292,36 @@ interp_lookup (const char *name)
   return NULL;
 }
 
+/* See interps.h.  */
+
+struct interp *
+interp_lookup (struct ui *ui, const char *name)
+{
+  struct interp_factory *factory;
+  struct interp *interp;
+  int ix;
+
+  if (name == NULL || strlen (name) == 0)
+    return NULL;
+
+  /* Only create each interpreter once per top level.  */
+  interp = interp_lookup_existing (ui, name);
+  if (interp != NULL)
+    return interp;
+
+  for (ix = 0;
+       VEC_iterate (interp_factory_p, interpreter_factories, ix, factory);
+       ++ix)
+    if (strcmp (factory->name, name) == 0)
+      {
+	interp = factory->func (name);
+	interp_add (ui, interp);
+	return interp;
+      }
+
+  return NULL;
+}
+
 /* Returns the current interpreter.  */
 
 struct ui_out *
@@ -273,7 +353,7 @@ struct interp *
 interp_set_temp (const char *name)
 {
   struct ui_interp_info *ui_interp = get_current_interp_info ();
-  struct interp *interp = interp_lookup (name);
+  struct interp *interp = interp_lookup (current_ui, name);
   struct interp *old_interp = ui_interp->current_interpreter;
 
   if (interp)
@@ -433,7 +513,7 @@ interpreter_exec_cmd (char *args, int from_tty)
 
   old_interp = ui_interp->current_interpreter;
 
-  interp_to_use = interp_lookup (prules[0]);
+  interp_to_use = interp_lookup (current_ui, prules[0]);
   if (interp_to_use == NULL)
     error (_("Could not find interpreter \"%s\"."), prules[0]);
 
@@ -469,15 +549,15 @@ static VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
-  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct interp_factory *interp;
   int textlen;
   VEC (char_ptr) *matches = NULL;
-  struct interp *interp;
+  int ix;
 
   textlen = strlen (text);
-  for (interp = ui_interp->interp_list;
-       interp != NULL;
-       interp = interp->next)
+  for (ix = 0;
+       VEC_iterate (interp_factory_p, interpreter_factories, ix, interp);
+       ++ix)
     {
       if (strncmp (interp->name, text, textlen) == 0)
 	{
diff --git a/gdb/interps.h b/gdb/interps.h
index f0badc5..e5cd779 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -24,6 +24,16 @@
 
 struct ui_out;
 struct interp;
+struct ui;
+
+typedef struct interp *(*interp_factory_func) (const char *name);
+
+/* Each interpreter kind (CLI, MI, etc.) registers itself with a call
+   to this function, passing along its name, and a pointer to a
+   function that creates a new instance of an interpreter with that
+   name.  */
+extern void interp_factory_register (const char *name,
+				     interp_factory_func func);
 
 extern int interp_resume (struct interp *interp);
 extern int interp_suspend (struct interp *interp);
@@ -64,10 +74,18 @@ struct interp_procs
   interp_command_loop_ftype *command_loop_proc;
 };
 
-extern struct interp *interp_new (const char *name, const struct interp_procs *procs);
-extern void interp_add (struct interp *interp);
+extern struct interp *interp_new (const char *name,
+				  const struct interp_procs *procs,
+				  void *data);
+extern void interp_add (struct ui *ui, struct interp *interp);
 extern int interp_set (struct interp *interp, int top_level);
-extern struct interp *interp_lookup (const char *name);
+
+/* Look up the interpreter for NAME, creating one if none exists yet.
+   If NAME is not a interpreter type previously registered with
+   interp_factory_register, return NULL; otherwise return a pointer to
+   the interpreter.  */
+extern struct interp *interp_lookup (struct ui *ui, const char *name);
+
 extern struct ui_out *interp_ui_out (struct interp *interp);
 extern void *interp_data (struct interp *interp);
 extern const char *interp_name (struct interp *interp);
diff --git a/gdb/main.c b/gdb/main.c
index d84340e..221888d 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -962,7 +962,7 @@ captured_main (void *data)
 
   {
     /* Find it.  */
-    struct interp *interp = interp_lookup (interpreter_p);
+    struct interp *interp = interp_lookup (current_ui, interpreter_p);
 
     if (interp == NULL)
       error (_("Interpreter `%s' unrecognized"), interpreter_p);
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 7c82950..d24bf85 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -237,7 +237,7 @@ mi_cmd_interpreter_exec (char *command, char **argv, int argc)
     error (_("-interpreter-exec: "
 	     "Usage: -interpreter-exec interp command"));
 
-  interp_to_use = interp_lookup (argv[0]);
+  interp_to_use = interp_lookup (current_ui, argv[0]);
   if (interp_to_use == NULL)
     error (_("-interpreter-exec: could not find interpreter \"%s\""),
 	   argv[0]);
@@ -1219,25 +1219,35 @@ mi_set_logging (struct interp *interp, int start_log,
   return 1;
 }
 
+/* The MI interpreter's vtable.  */
+
+static const struct interp_procs mi_interp_procs =
+{
+  mi_interpreter_init,		/* init_proc */
+  mi_interpreter_resume,	/* resume_proc */
+  mi_interpreter_suspend,	/* suspend_proc */
+  mi_interpreter_exec,		/* exec_proc */
+  mi_ui_out, 			/* ui_out_proc */
+  mi_set_logging,		/* set_logging_proc */
+  mi_command_loop		/* command_loop_proc */
+};
+
+/* Factory for MI interpreters.  */
+
+static struct interp *
+mi_interp_factory (const char *name)
+{
+  return interp_new (name, &mi_interp_procs, NULL);
+}
+
 extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
 
 void
 _initialize_mi_interp (void)
 {
-  static const struct interp_procs procs =
-    {
-      mi_interpreter_init,	/* init_proc */
-      mi_interpreter_resume,	/* resume_proc */
-      mi_interpreter_suspend,	/* suspend_proc */
-      mi_interpreter_exec,	/* exec_proc */
-      mi_ui_out, 		/* ui_out_proc */
-      mi_set_logging,		/* set_logging_proc */
-      mi_command_loop		/* command_loop_proc */
-    };
-
   /* The various interpreter levels.  */
-  interp_add (interp_new (INTERP_MI1, &procs));
-  interp_add (interp_new (INTERP_MI2, &procs));
-  interp_add (interp_new (INTERP_MI3, &procs));
-  interp_add (interp_new (INTERP_MI, &procs));
+  interp_factory_register (INTERP_MI1, mi_interp_factory);
+  interp_factory_register (INTERP_MI2, mi_interp_factory);
+  interp_factory_register (INTERP_MI3, mi_interp_factory);
+  interp_factory_register (INTERP_MI, mi_interp_factory);
 }
diff --git a/gdb/python/python.c b/gdb/python/python.c
index fa1c78e..a66f6f0 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -656,7 +656,7 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
       make_cleanup_restore_ui_out (&current_uiout);
       /* Use the console interpreter uiout to have the same print format
 	for console or MI.  */
-      interp = interp_lookup ("console");
+      interp = interp_lookup (current_ui, "console");
       current_uiout = interp_ui_out (interp);
 
       prevent_dont_repeat ();
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 7a0da48..7544500 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -138,6 +138,9 @@ tui_init (struct interp *self, int top_level)
   /* Install exit handler to leave the screen in a good shape.  */
   atexit (tui_exit);
 
+  if (top_level)
+    tui_interp = self;
+
   tui_initialize_static_data ();
 
   tui_initialize_io ();
@@ -207,25 +210,34 @@ tui_exec (void *data, const char *command_str)
   internal_error (__FILE__, __LINE__, _("tui_exec called"));
 }
 
+/* The TUI interpreter's vtable.  */
+
+static const struct interp_procs tui_interp_procs = {
+  tui_init,
+  tui_resume,
+  tui_suspend,
+  tui_exec,
+  tui_ui_out,
+  NULL,
+  cli_command_loop
+};
+
+/* Factory for TUI interpreters.  */
+
+static struct interp *
+tui_interp_factory (const char *name)
+{
+  return interp_new (name, &tui_interp_procs, NULL);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_tui_interp;
 
 void
 _initialize_tui_interp (void)
 {
-  static const struct interp_procs procs = {
-    tui_init,
-    tui_resume,
-    tui_suspend,
-    tui_exec,
-    tui_ui_out,
-    NULL,
-    cli_command_loop
-  };
-
-  /* Create a default uiout builder for the TUI.  */
-  tui_interp = interp_new (INTERP_TUI, &procs);
-  interp_add (tui_interp);
+  interp_factory_register (INTERP_TUI, tui_interp_factory);
+
   if (interpreter_p && strcmp (interpreter_p, INTERP_TUI) == 0)
     tui_start_enabled = 1;
 
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 07/34] Make the intepreters output to all UIs
  2016-05-19 15:16   ` Simon Marchi
@ 2016-05-26 18:12     ` Pedro Alves
  0 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:12 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 05/19/2016 04:15 PM, Simon Marchi wrote:
> On 16-05-06 08:34 AM, Pedro Alves wrote:

>> +  /* Traverse through all UI, and switch the current UI to the one
>> +     being iterated.  */
>> +#define SWITCH_THRU_ALL_UIS(STATE)		\
>> +  for (switch_thru_all_uis_init (&STATE);		\
>> +       switch_thru_all_uis_cond (&STATE);		\
>> +       switch_thru_all_uis_next (&STATE))		\
> 
> The last backslash is not necessary I think.

Thanks, indeed.  I've removed it.

> 
> I was wondering why you did not name this "ALL_UIS", using the same pattern
> as ALL_INFERIORS & al, but then I realized it's because this one actually
> sets current_ui before each iteration (and restores it at the end).

Exactly.

> 
> I guess the reason you need to do this is because, again, everything relies on
> accessing the global current_ui, whereas it should be passed down as a parameter.

It goes deeper than straight access of current_ui directly.  It goes all the
way to gdb_stdout, etc., which are really fields of current_ui.  I don't
ever see us passing down a current_ui to _all_ functions that might want
to do I/O.  That'd mean passing it around _everywhere_.  So basically, if
you're calling a function that may do output, and you want that output
to be duplicated to all UIs, you need to use SWITCH_THRU_ALL_UIS.
Note, we can't just call such functions once, with output redirected to
a buffer, and then print that buffer on all UI's streams, because each
UI's ui_out may want to print differently, and also run through distinct
code paths, due to ui_out_is_mi_like_p.

> I am not saying it should be done in this series (it's a big task in itself), but
> we can probably tackle it after.  They way you did things should make it easy to
> improve things later on.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 08/34] Always run async signal handlers in the main UI
  2016-05-19 19:28   ` Simon Marchi
@ 2016-05-26 18:13     ` Pedro Alves
  2016-05-26 18:15       ` Simon Marchi
  0 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:13 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 05/19/2016 08:28 PM, Simon Marchi wrote:
> On 16-05-06 08:34 AM, Pedro Alves wrote:

>> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
>> -   It always exists and is created automatically when GDB starts
>> -   up.  */
>> +/* The main UI.  */
>>  static struct ui main_ui_;
>>  
>> +struct ui *main_ui = &main_ui_;
> 
> I'd suggest making the pointer const, to show (and make sure) that the main ui
> never changes throughout the lifetime of the gdb instance:
> 
>   +struct ui * const main_ui = &main_ui_;

Hmm, that wouldn't work, because later on the series, main_ui
becomes heap allocated:

  https://sourceware.org/ml/gdb-patches/2016-05/msg00125.html

Guess we could instead have:

 struct ui *get_main_ui (void);

To make it clearer that this is not supposed to be an lvalue.

And likewise maybe:

 struct ui *get_current_ui (void);
 void set_current_ui (struct ui *);

Though unless I'm in for some other major rework of the series,
at this point I'd rather defer that to a follow up patch.
I've gone through renaming these objects throughout the whole
series a few times already, and it's quite painful.  WDYT?

> 
>>  struct ui *current_ui = &main_ui_;
>>  struct ui *ui_list = &main_ui_;
> 
> ui_list could be const for the same reason, while we're at it.
> 

Likewise, this becomes heap allocated.  (I don't see much point
in changing this one, the only point of making it extern is
to be able to access it in the implementation of ALL_UIS.)

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 08/34] Always run async signal handlers in the main UI
  2016-05-26 18:13     ` Pedro Alves
@ 2016-05-26 18:15       ` Simon Marchi
  0 siblings, 0 replies; 72+ messages in thread
From: Simon Marchi @ 2016-05-26 18:15 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-26 02:13 PM, Pedro Alves wrote:
> On 05/19/2016 08:28 PM, Simon Marchi wrote:
>> On 16-05-06 08:34 AM, Pedro Alves wrote:
> 
>>> -/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
>>> -   It always exists and is created automatically when GDB starts
>>> -   up.  */
>>> +/* The main UI.  */
>>>  static struct ui main_ui_;
>>>  
>>> +struct ui *main_ui = &main_ui_;
>>
>> I'd suggest making the pointer const, to show (and make sure) that the main ui
>> never changes throughout the lifetime of the gdb instance:
>>
>>   +struct ui * const main_ui = &main_ui_;
> 
> Hmm, that wouldn't work, because later on the series, main_ui
> becomes heap allocated:
> 
>   https://sourceware.org/ml/gdb-patches/2016-05/msg00125.html
> 
> Guess we could instead have:
> 
>  struct ui *get_main_ui (void);
> 
> To make it clearer that this is not supposed to be an lvalue.
> 
> And likewise maybe:
> 
>  struct ui *get_current_ui (void);
>  void set_current_ui (struct ui *);
> 
> Though unless I'm in for some other major rework of the series,
> at this point I'd rather defer that to a follow up patch.
> I've gone through renaming these objects throughout the whole
> series a few times already, and it's quite painful.  WDYT?

No problem, I mentioned that without seeing the big picture, so you know better.

Simon

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 29/34] Add new command to create extra console/mi UI channels
  2016-05-06 12:35 ` [PATCH v3 29/34] Add new command to create extra console/mi UI channels Pedro Alves
@ 2016-05-26 18:34   ` Pedro Alves
  0 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:34 UTC (permalink / raw)
  To: gdb-patches

Here's a tiny update of this patch, that makes "new-ui"
a non-repeating command.  Just a dont_repeat(); call.

Marc had pointed this out to me in v2, but I missed adding
it in v3.

I wrote a new test that covers this and more, that I'm tacking
onto the end of the series.

From cdfa7f344a83825f195c45f6121af4dcef21fd14 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 26 May 2016 13:08:19 +0100
Subject: [PATCH] Add new command to create extra console/mi UIs

With all the previous plumbing in place, it's now easy to add a
command that actually creates a new console/mi UI.

The intended use case is to make it possible and easy for MI frontends
to provide a fully featured GDB console to users, with readline
support, command line editing, history, etc., just like if gdb was
started on the command line.  Currently MI frontends have to try to
implement all of that theirselves and make use of "-interpreter-exec
console ...", which is far from perfect.  If you ever tried Eclipse's
gdb console window, you'll know what I mean...

Instead of trying to multiplex console through MI, this command let's
just leverage all the built in readline/editing support already inside
gdb.

The plan is for the MI frontend to start GDB in regular console mode,
running inside a terminal emulator widget embedded in Eclipse (which
already exists, for supporting the shell widget; other frontends have
similar widgets), and then tell GDB to run a full MI interpreter on an
specified input/output device, independent of the console.

My original prototype planned to do things the other way around --
start GDB in MI mode, and then start an extra CLI console on separate
tty.  I handed over that prototype to Marc Khouzam @ Eclipse CDT, and
after experimentation and discussion, we ended up concluding that
starting GDB in CLI mode instead was both easier and actually also
supported an interesting use case -- connect an Eclipse frontend to a
GDB that is already running outside Eclipse.

The current usage is "new-ui <interpreter> <tty>".

E.g., on a terminal run this scriplet:

 $ cat gdb-client
 #!/bin/bash

 reset
 tty
 tail -f /dev/null

 $ gdb-client
 /dev/pts/15

Now run gdb on another terminal, and tell it to start a MI interpreter
on the tty of the other terminal:

 ...
 (gdb) new-ui mi /dev/pts/15
 New UI allocated

Now back to the the gdb-client terminal, we'll get an MI prompt, ready
for MI input:

 /dev/pts/15
 =thread-group-added,id="i1"
 (gdb)

You can also start a new UI running a CLI, with:

 (gdb) new-ui console /dev/pts/15

Though note that this console won't support readline command editing.
It works as if "set editing off" was entered.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* interps.c (set_top_level_interpreter): New function, factored
	out from captured_main.
	(interpreter_completer): Make extern.
	* interps.h (set_top_level_interpreter, interpreter_completer):
	New declarations.
	(captured_main): Use set_top_level_interpreter.
	* top.c [!O_NOCTTY] (O_NOCTTY): Define as 0.
	(open_terminal_stream, new_ui_command): New functions.
	(init_main): Install the "new-ui" command.
---
 gdb/interps.c | 20 ++++++++++++--
 gdb/interps.h | 11 ++++++++
 gdb/main.c    | 12 +--------
 gdb/top.c     | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+), 13 deletions(-)

diff --git a/gdb/interps.c b/gdb/interps.c
index fdf1479..163c837 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -319,6 +319,21 @@ interp_lookup (struct ui *ui, const char *name)
   return NULL;
 }
 
+/* See interps.h.  */
+
+void
+set_top_level_interpreter (const char *name)
+{
+  /* Find it.  */
+  struct interp *interp = interp_lookup (current_ui, name);
+
+  if (interp == NULL)
+    error (_("Interpreter `%s' unrecognized"), name);
+  /* Install it.  */
+  if (!interp_set (interp, 1))
+    error (_("Interpreter `%s' failed to initialize."), name);
+}
+
 /* Returns the current interpreter.  */
 
 struct ui_out *
@@ -550,8 +565,9 @@ interpreter_exec_cmd (char *args, int from_tty)
   do_cleanups (cleanup);
 }
 
-/* List the possible interpreters which could complete the given text.  */
-static VEC (char_ptr) *
+/* See interps.h.  */
+
+VEC (char_ptr) *
 interpreter_completer (struct cmd_list_element *ignore,
 		       const char *text, const char *word)
 {
diff --git a/gdb/interps.h b/gdb/interps.h
index 4ac0845..97d510f 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -95,6 +95,11 @@ extern int interp_set (struct interp *interp, int top_level);
    the interpreter.  */
 extern struct interp *interp_lookup (struct ui *ui, const char *name);
 
+/* Set the current UI's top level interpreter to the interpreter named
+   NAME.  Throws an error if NAME is not a known interpreter or the
+   interpreter fails to initialize.  */
+extern void set_top_level_interpreter (const char *name);
+
 extern struct ui_out *interp_ui_out (struct interp *interp);
 extern void *interp_data (struct interp *interp);
 extern const char *interp_name (struct interp *interp);
@@ -131,6 +136,12 @@ extern int interp_supports_command_editing (struct interp *interp);
    chance to e.g., print a prompt.  */
 extern void interp_pre_command_loop (struct interp *interp);
 
+/* List the possible interpreters which could complete the given
+   text.  */
+extern VEC (char_ptr) *interpreter_completer (struct cmd_list_element *ignore,
+					      const char *text,
+					      const char *word);
+
 /* well-known interpreters */
 #define INTERP_CONSOLE		"console"
 #define INTERP_MI1             "mi1"
diff --git a/gdb/main.c b/gdb/main.c
index 947ed55..5477379 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -963,17 +963,7 @@ captured_main (void *data)
 
   /* Install the default UI.  All the interpreters should have had a
      look at things by now.  Initialize the default interpreter.  */
-
-  {
-    /* Find it.  */
-    struct interp *interp = interp_lookup (current_ui, interpreter_p);
-
-    if (interp == NULL)
-      error (_("Interpreter `%s' unrecognized"), interpreter_p);
-    /* Install it.  */
-    if (!interp_set (interp, 1))
-      error (_("Interpreter `%s' failed to initialize."), interpreter_p);
-  }
+  set_top_level_interpreter (interpreter_p);
 
   /* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets
      GDB retain the old MI1 interpreter startup behavior.  Output the
diff --git a/gdb/top.c b/gdb/top.c
index 7506c45..3174f3c 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -74,6 +74,10 @@
 # include "tui/tui.h"
 #endif
 
+#ifndef O_NOCTTY
+# define O_NOCTTY 0
+#endif
+
 extern void initialize_all_files (void);
 
 #define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
@@ -320,6 +324,79 @@ delete_ui (struct ui *todel)
   free_ui (ui);
 }
 
+/* Open file named NAME for read/write, making sure not to make it the
+   controlling terminal.  */
+
+static FILE *
+open_terminal_stream (const char *name)
+{
+  int fd;
+
+  fd = open (name, O_RDWR | O_NOCTTY);
+  if (fd < 0)
+    perror_with_name  (_("opening terminal failed"));
+
+  return fdopen (fd, "w+");
+}
+
+/* Implementation of the "new-ui" command.  */
+
+static void
+new_ui_command (char *args, int from_tty)
+{
+  struct ui *ui;
+  struct interp *interp;
+  FILE *stream[3] = { NULL, NULL, NULL };
+  int i;
+  int res;
+  int argc;
+  char **argv;
+  const char *interpreter_name;
+  const char *tty_name;
+  struct cleanup *back_to;
+  struct cleanup *streams_chain;
+
+  dont_repeat ();
+
+  argv = gdb_buildargv (args);
+  back_to = make_cleanup_freeargv (argv);
+  argc = countargv (argv);
+
+  if (argc < 2)
+    error (_("usage: new-ui <interpreter> <tty>"));
+
+  interpreter_name = argv[0];
+  tty_name = argv[1];
+
+  streams_chain = make_cleanup (null_cleanup, NULL);
+
+  /* Open specified terminal, once for each of
+     stdin/stdout/stderr.  */
+  for (i = 0; i < 3; i++)
+    {
+      stream[i] = open_terminal_stream (tty_name);
+      make_cleanup_fclose (stream[i]);
+    }
+
+  ui = new_ui (stream[0], stream[1], stream[2]);
+
+  discard_cleanups (streams_chain);
+
+  ui->async = 1;
+
+  make_cleanup (restore_ui_cleanup, current_ui);
+  current_ui = ui;
+
+  set_top_level_interpreter (interpreter_name);
+
+  interp_pre_command_loop (top_level_interpreter ());
+
+  /* This restores the previous UI.  */
+  do_cleanups (back_to);
+
+  printf_unfiltered ("New UI allocated\n");
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
@@ -1923,6 +2000,8 @@ set_history_filename (char *args, int from_tty, struct cmd_list_element *c)
 static void
 init_main (void)
 {
+  struct cmd_list_element *c;
+
   /* Initialize the prompt to a simple "(gdb) " prompt or to whatever
      the DEFAULT_PROMPT is.  */
   set_prompt (DEFAULT_PROMPT);
@@ -2060,6 +2139,12 @@ input settings."),
                         NULL,
                         show_interactive_mode,
                         &setlist, &showlist);
+
+  c = add_cmd ("new-ui", class_support, new_ui_command, _("\
+Create a new UI.  It takes two arguments:\n\
+The first argument is the name of the interpreter to run.\n\
+The second argument is the terminal the UI runs on.\n"), &cmdlist);
+  set_cmd_completer (c, interpreter_completer);
 }
 
 void
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v3 35/34] Add "new-ui console" tests
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (33 preceding siblings ...)
  2016-05-06 12:53 ` [PATCH v3 19/34] Simplify starting the command event loop Pedro Alves
@ 2016-05-26 18:37 ` Pedro Alves
  2016-06-21  0:23 ` [pushed] Re: [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-05-26 18:37 UTC (permalink / raw)
  To: gdb-patches

I'm adding this one to the series to cover a few bugs
that were pointed out in earlier reviews, and more.

From 19266f547086ae4f25900c1eeb10796f8951ee40 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 26 May 2016 13:12:32 +0100
Subject: [PATCH] Add "new-ui console" tests

This adds a test that uses new-ui to create a secondary console, and
then runs some basic smoke tests.  It ensures that:

 - synchronous commands send output to the UI that initiated it

 - asynchronous events like breakpoint hits are reported on all
   consoles.

 - "new-ui" without arguments doesn't crash.

 - The "new-ui" command doesn't repeat.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

        * gdb.base/new-ui.c: New file.
	* gdb.base/new-ui.exp: New file.
	* lib/mi-support.exp (switch_gdb_spawn_id): Move to ...
	* lib/gdb.exp (switch_gdb_spawn_id): ... here.
	(with_spawn_id): New procedure.
---
 gdb/testsuite/gdb.base/new-ui.c   |  42 +++++++++++
 gdb/testsuite/gdb.base/new-ui.exp | 146 ++++++++++++++++++++++++++++++++++++++
 gdb/testsuite/lib/gdb.exp         |  32 +++++++++
 gdb/testsuite/lib/mi-support.exp  |  12 ----
 4 files changed, 220 insertions(+), 12 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/new-ui.c
 create mode 100644 gdb/testsuite/gdb.base/new-ui.exp

diff --git a/gdb/testsuite/gdb.base/new-ui.c b/gdb/testsuite/gdb.base/new-ui.c
new file mode 100644
index 0000000..8fff0bc
--- /dev/null
+++ b/gdb/testsuite/gdb.base/new-ui.c
@@ -0,0 +1,42 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2016 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+volatile int global = 0;
+
+int
+main (void)
+{
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1; /* set break main console here */
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1;
+  global = 1; /* set break extra console here */
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/new-ui.exp b/gdb/testsuite/gdb.base/new-ui.exp
new file mode 100644
index 0000000..f3f66db
--- /dev/null
+++ b/gdb/testsuite/gdb.base/new-ui.exp
@@ -0,0 +1,146 @@
+# Copyright 2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile
+
+set compile_options "debug"
+if {[build_executable $testfile.exp $testfile ${srcfile} ${compile_options}] == -1} {
+    untested "failed to compile $testfile"
+    return -1
+}
+
+# Ensure no output has been sent.  Use MESSAGE as test message.
+
+proc ensure_no_output {message} {
+    global decimal
+
+    # Run a command and use an anchor to make sure no output appears
+    # before the command's expected output.
+    gdb_test "print 999" "^print 999\r\n\\\$$decimal = 999" $message
+}
+
+# Run a few execution-related commands on CON1, and ensure the proper
+# output, or none, if appropriate, is sent to CON2.  CON1_NAME and
+# CON2_NAME are the names of the consoles.
+
+proc do_execution_tests {con1 con1_name con2 con2_name} {
+    global srcfile
+    global decimal
+
+    set bp_lineno [gdb_get_line_number "set break $con1_name here"]
+
+    with_spawn_id $con1 {
+	gdb_test "next" "global = 1;"
+    }
+    with_spawn_id $con2 {
+	ensure_no_output "next causes no spurious output on other console"
+    }
+
+    with_spawn_id $con1 {
+	gdb_test "break $srcfile:$bp_lineno" \
+	    "Breakpoint $decimal .*$srcfile, line $bp_lineno\\." \
+	    "set breakpoint"
+    }
+    with_spawn_id $con2 {
+	ensure_no_output "break causes no spurious output on other console"
+    }
+
+    with_spawn_id $con1 {
+	gdb_test "continue" "set break $con1_name here .*" "continue to breakpoint"
+    }
+
+    with_spawn_id $con2 {
+	set test "breakpoint hit reported on other console"
+	gdb_test_multiple "" $test {
+	    -re "Breakpoint $decimal, .* set break $con1_name here " {
+		pass $test
+	    }
+	}
+    }
+}
+
+# The test proper.
+
+proc do_test {} {
+    global srcfile testfile
+    global gdb_prompt
+    global gdb_spawn_id
+    global gdb_main_spawn_id extra_spawn_id
+
+    clean_restart $testfile
+
+    if ![runto_main] {
+	untested "could not run to main"
+	return -1
+    }
+
+    gdb_test "new-ui" \
+	"usage: new-ui <interpreter> <tty>" \
+	"new-ui without arguments"
+
+    set test "new-ui does not repeat"
+    send_gdb "\n"
+    gdb_test_multiple "" $test {
+	-re "^\r\n$gdb_prompt $" {
+	    pass $test
+	}
+    }
+
+    # Save the main UI's spawn ID.
+    set gdb_main_spawn_id $gdb_spawn_id
+
+    # Create the new PTY for the secondary console UI.
+    spawn -pty
+    set extra_spawn_id $spawn_id
+    set extra_tty_name $spawn_out(slave,name)
+    gdb_test_multiple "new-ui console $extra_tty_name" "new-ui" {
+	-re "New UI allocated\r\n$gdb_prompt $" {
+	}
+    }
+
+    with_spawn_id $extra_spawn_id {
+	set test "initial prompt on extra console"
+	gdb_test_multiple "" $test {
+	    -re "$gdb_prompt $" {
+		pass $test
+	    }
+	}
+    }
+
+    # Ensure non-execution commands in one console don't cause output
+    # in the other consoles.
+    with_spawn_id $gdb_main_spawn_id {
+	gdb_test "print 1" "^print 1\r\n\\\$1 = 1" "print on main console"
+    }
+    with_spawn_id $extra_spawn_id {
+	gdb_test "print 2" "^print 2\r\n\\\$2 = 2" "print on extra console"
+    }
+
+    # Run a few execution tests with the main console as the driver
+    # console.
+    with_test_prefix "main console" {
+	do_execution_tests \
+	    $gdb_main_spawn_id "main console" \
+	    $extra_spawn_id "extra console"
+    }
+    # Same, but with the extra console as driver.
+    with_test_prefix "extra console" {
+	do_execution_tests \
+	    $extra_spawn_id "extra console" \
+	    $gdb_main_spawn_id "main console"
+    }
+}
+
+do_test
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index a374370..40de630 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -2070,6 +2070,38 @@ proc with_target_charset { target_charset body } {
     }
 }
 
+# Switch the default spawn id to SPAWN_ID, so that gdb_test,
+# mi_gdb_test etc. default to using it.
+
+proc switch_gdb_spawn_id {spawn_id} {
+    global gdb_spawn_id
+    global board board_info
+
+    set gdb_spawn_id $spawn_id
+    set board [host_info name]
+    set board_info($board,fileid) $spawn_id
+}
+
+# Run BODY with SPAWN_ID as current spawn id.
+
+proc with_spawn_id { spawn_id body } {
+    global gdb_spawn_id
+
+    set saved_spawn_id $gdb_spawn_id
+    switch_gdb_spawn_id $spawn_id
+
+    set code [catch {uplevel 1 $body} result]
+
+    switch_gdb_spawn_id $saved_spawn_id
+
+    if {$code == 1} {
+	global errorInfo errorCode
+	return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+	return -code $code $result
+    }
+}
+
 # Select the largest timeout from all the timeouts:
 # - the local "timeout" variable of the scope two levels above,
 # - the global "timeout" variable,
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index edfc07d..7b5c90b 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -122,18 +122,6 @@ proc mi_create_inferior_pty {} {
     }
 }
 
-# Switch the default spawn id to SPAWN_ID, so that mi_gdb_test
-# etc. default to using it.
-
-proc switch_gdb_spawn_id {spawn_id} {
-    global gdb_spawn_id
-    global board board_info
-
-    set gdb_spawn_id $spawn_id
-    set board [host_info name]
-    set board_info($board,fileid) $spawn_id
-}
-
 proc mi_gdb_start_separate_mi_tty { args } {
     global gdb_prompt mi_gdb_prompt
     global timeout
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels
  2016-05-26 11:11     ` Pedro Alves
@ 2016-06-17 17:24       ` Pedro Alves
  2016-06-17 20:02         ` Eli Zaretskii
  0 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-06-17 17:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 05/26/2016 12:11 PM, Pedro Alves wrote:
> On 05/06/2016 02:04 PM, Eli Zaretskii wrote:
>>> From: Pedro Alves <palves@redhat.com>
>>> Date: Fri,  6 May 2016 13:35:00 +0100
>>>
>>> +Although you may only choose a single interpreter at startup, it is
>>> +possible to run an independent interpreter on a separate channel.
>>
>> "Channel"?  What's that?  Can we find a better word?
>>
>> No other comments to the doc part.  Thanks.
> 
> Thanks Eli.  Here's an attempt at clarifying things, using
> the same terminology already used in other related commands.

Hi Eli.  I'm not sure whether the "no other comments" remark
meant pre-approval, or whether this slipped through
the cracks.  FAOD, is the below OK?

Thanks,
Pedro Alves

> 
> From b58b402641e5cb5d0cbdf3bc2a815ada244be4c5 Mon Sep 17 00:00:00 2001
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 5 May 2016 13:06:03 +0100
> Subject: [PATCH 30/34] [DOC] Document support for running interpreters on
>  separate UIs
> 
> gdb/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* NEWS: Mention support for running interpreters on separate
> 	UIs and the new new-ui command.
> 
> gdb/doc/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* gdb.texinfo (Interpreters): Update intepreter-exec section,
> 	document new-ui and explain use case.
> ---
>  gdb/doc/gdb.texinfo | 56 +++++++++++++++++++++++++++++++++++++++++++----------
>  gdb/NEWS            | 18 +++++++++++++++++
>  2 files changed, 64 insertions(+), 10 deletions(-)
> 
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index f74c41c..a302d6e 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -24805,18 +24805,11 @@ The @sc{gdb/mi} interface included in @value{GDBN} 5.1, 5.2, and 5.3.
>  @end table
>  
>  @cindex invoke another interpreter
> -The interpreter being used by @value{GDBN} may not be dynamically
> -switched at runtime.  Although possible, this could lead to a very
> -precarious situation.  Consider an IDE using @sc{gdb/mi}.  If a user
> -enters the command "interpreter-set console" in a console view,
> -@value{GDBN} would switch to using the console interpreter, rendering
> -the IDE inoperable!
>  
>  @kindex interpreter-exec
> -Although you may only choose a single interpreter at startup, you may execute
> -commands in any interpreter from the current interpreter using the appropriate
> -command.  If you are running the console interpreter, simply use the
> -@code{interpreter-exec} command:
> +You may execute commands in any interpreter from the current
> +interpreter using the appropriate command.  If you are running the
> +console interpreter, simply use the @code{interpreter-exec} command:
>  
>  @smallexample
>  interpreter-exec mi "-data-list-register-names"
> @@ -24825,6 +24818,49 @@ interpreter-exec mi "-data-list-register-names"
>  @sc{gdb/mi} has a similar command, although it is only available in versions of
>  @value{GDBN} which support @sc{gdb/mi} version 2 (or greater).
>  
> +Note that @code{interpreter-exec} only changes the interpreter for the
> +duration of the specified command.  It does not change the interpreter
> +permanently.
> +
> +@cindex start a new independent interpreter
> +
> +Although you may only choose a single interpreter at startup, it is
> +possible to run an independent interpreter on a specified input/output
> +device (usually a tty).
> +
> +For example, consider a debugger GUI or IDE that wants to provide a
> +@value{GDBN} console view.  It may do so by embedding a terminal
> +emulator widget in its GUI, starting @value{GDBN} in the traditional
> +command-line mode with stdin/stdout/stderr redirected to that
> +terminal, and then creating an MI interpreter running on a specified
> +input/output device.  The console interpreter created by @value{GDBN}
> +at startup handles commands the user types in the terminal widget,
> +while the GUI controls and synchronizes state with @value{GDBN} using
> +the separate MI interpreter.
> +
> +To start a new secondary @dfn{user interface} running MI, use the
> +@code{new-ui} command:
> +
> +@kindex new-ui
> +@cindex new user interface
> +@smallexample
> +new-ui @var{interpreter} @var{tty}
> +@end smallexample
> +
> +The @var{interpreter} parameter specifies the interpreter to run.
> +This accepts the same values as the @code{interpreter-exec} command.
> +For example, @samp{console}, @samp{mi}, @samp{mi2}, etc.  The
> +@var{tty} parameter specifies the name of the bidirectional file the
> +interpreter uses for input/output, usually the name of a
> +pseudoterminal slave on Unix systems.  For example:
> +
> +@smallexample
> +(@value{GDBP}) new-ui mi /dev/pts/9
> +@end smallexample
> +
> +@noindent
> +runs an MI interpreter on @file{/dev/pts/9}.
> +
>  @node TUI
>  @chapter @value{GDBN} Text User Interface
>  @cindex TUI
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 7bf1e1a..c6ed63d 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -27,6 +27,20 @@
>     Bounds: [lower = 0x7fffffffc390, upper = 0x7fffffffc3a3]
>     0x0000000000400d7c in upper () at i386-mpx-sigsegv.c:68
>  
> +* Support for running interpreters on specified input/output devices
> +
> +  GDB now supports a new mechanism that allows frontends to provide
> +  fully featured GDB console views, as a better alternative to
> +  building such views on top of the "-interpreter-exec console"
> +  command.  See the new "new-ui" command below.  With that command,
> +  frontends can now start GDB in the traditional command-line mode
> +  running in an embedded terminal emulator widget, and create a
> +  separate MI interpreter running on a specified i/o device.  In this
> +  way, GDB handles line editing, history, tab completion, etc. in the
> +  console all by itself, and the GUI uses the separate MI interpreter
> +  for its own control and synchronization, invisible to the command
> +  line.
> +
>  * New commands
>  
>  skip -file file
> @@ -40,6 +54,10 @@ skip -rfunction regular-expression
>  maint info line-table REGEXP
>    Display the contents of GDB's internal line table data struture.
>  
> +new-ui INTERP TTY
> +  Start a new user interface instance running INTERP as interpreter,
> +  using the TTY file for input/output.
> +
>  * Support for tracepoints and fast tracepoints on s390-linux and s390x-linux
>    was added in GDBserver, including JIT compiling fast tracepoint's
>    conditional expression bytecode into native code.
> 

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels
  2016-06-17 17:24       ` Pedro Alves
@ 2016-06-17 20:02         ` Eli Zaretskii
  0 siblings, 0 replies; 72+ messages in thread
From: Eli Zaretskii @ 2016-06-17 20:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Fri, 17 Jun 2016 18:24:05 +0100
> 
> On 05/26/2016 12:11 PM, Pedro Alves wrote:
> > On 05/06/2016 02:04 PM, Eli Zaretskii wrote:
> >>> From: Pedro Alves <palves@redhat.com>
> >>> Date: Fri,  6 May 2016 13:35:00 +0100
> >>>
> >>> +Although you may only choose a single interpreter at startup, it is
> >>> +possible to run an independent interpreter on a separate channel.
> >>
> >> "Channel"?  What's that?  Can we find a better word?
> >>
> >> No other comments to the doc part.  Thanks.
> > 
> > Thanks Eli.  Here's an attempt at clarifying things, using
> > the same terminology already used in other related commands.
> 
> Hi Eli.  I'm not sure whether the "no other comments" remark
> meant pre-approval

It does.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [pushed] Re: [PATCH v3 00/34] Towards great frontend GDB consoles
  2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
                   ` (34 preceding siblings ...)
  2016-05-26 18:37 ` [PATCH v3 35/34] Add "new-ui console" tests Pedro Alves
@ 2016-06-21  0:23 ` Pedro Alves
  35 siblings, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-06-21  0:23 UTC (permalink / raw)
  To: gdb-patches

FYI,

On 05/06/2016 01:34 PM, Pedro Alves wrote:

> This series provides a way to for frontends's GDB console to be on par
> with gdb's native console running on a terminal.
> 

I've pushed this to master now.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI
  2016-05-06 12:36 ` [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI Pedro Alves
@ 2016-06-28 20:19   ` Simon Marchi
  2016-06-29 10:50     ` Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-06-28 20:19 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-05-06 08:35 AM, Pedro Alves wrote:
> With this, a specific test may can start GDB with MI on a separate UI
> by using:
> 
>   mi_gdb_start separate-mi-tty
> 
> In addition, it's also possible to run the whole testsuite with MI on
> a separate tty, with:
> 
>  make check RUNTESTFLAGS="FORCE_SEPARATE_MI_TTY=1"
> 
> gdb_main_spawn_id and mi_spawn_id are added so that tests may expect
> output from either channel.
> 
> While at it, inferior_spawn_id was not being cleared when gdb exits,
> unlike the other spawn ids, thus a test that starts gdb more than once
> would end up using a stale spawn id.

Hi Pedro,

I think this commit breaks MI tests with native-gdbserver:

$ make check RUNTESTFLAGS="--target_board=native-gdbserver mi-var-child.exp"
...
Running /home/emaisin/build/binutils-gdb/gdb/testsuite/../../../../src/binutils-gdb/gdb/testsuite/gdb.mi/mi-var-child.exp ...
can't unset "inferior_spawn_id": no such variable
    while executing
"unset inferior_spawn_id"
    (procedure "close_gdbserver" line 20)
    invoked from within
"close_gdbserver"
...

I added a few traces to understand what's happening, and it seems that inferior_spawn_id
is being unset at two places:

>>> gdbserver-support.exp:gdb_exit called
>>> gdb.exp:default_gdb_exit called
>>> mi-support.exp:default_mi_gdb_start called
  *** set inferior_spawn_id to gdb_spawn_id exp8 in mi-support.exp:default_mi_gdb_start
>>> gdbserver-support.exp:gdbserver_start called
  *** set server_spawn_id in gdbserver-support.exp:gdbserver_start
  *** set inferior_spawn_id to server_spawn_id exp9 in gdbserver-support.exp.exp:gdbserver_start
>>> gdbserver-support.exp:gdbserver_start called
  *** set server_spawn_id in gdbserver-support.exp:gdbserver_start
  *** set inferior_spawn_id to server_spawn_id exp10 in gdbserver-support.exp.exp:gdbserver_start
>>> mi-support.exp:mi_uncatched_gdb_exit called
  *** unset inferior_spawn_id in mi-support.exp:mi_uncatched_gdb_exit
>>> gdbserver-support.exp:gdb_exit called
  *** unset server_spawn_id in gdbserver-support.exp:close_gdbserver
  *** unset inferior_spawn_id in gdbserver-support.exp:close_gdbserver  <--- This is the one that breaks.

The easy way would be to add a "info exists" check before unsetting it, but I don't know if
that would only hide a real problem.

Simon

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI
  2016-06-28 20:19   ` Simon Marchi
@ 2016-06-29 10:50     ` Pedro Alves
  2016-06-30 11:12       ` [pushed] Fix gdbserver/MI testing regression (was: Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI) Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-06-29 10:50 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 06/28/2016 09:19 PM, Simon Marchi wrote:

> I think this commit breaks MI tests with native-gdbserver:
> 
> $ make check RUNTESTFLAGS="--target_board=native-gdbserver mi-var-child.exp"
> ...
> Running /home/emaisin/build/binutils-gdb/gdb/testsuite/../../../../src/binutils-gdb/gdb/testsuite/gdb.mi/mi-var-child.exp ...
> can't unset "inferior_spawn_id": no such variable
>     while executing
> "unset inferior_spawn_id"
>     (procedure "close_gdbserver" line 20)
>     invoked from within
> "close_gdbserver"
> ...
> 

I can reproduce this.  Odd, maybe I made some last minute change
that went untested, not sure.  I'll take a look.

Thanks,
Pedro Alves

> I added a few traces to understand what's happening, and it seems that inferior_spawn_id
> is being unset at two places:
> 
>>>> gdbserver-support.exp:gdb_exit called
>>>> gdb.exp:default_gdb_exit called
>>>> mi-support.exp:default_mi_gdb_start called
>   *** set inferior_spawn_id to gdb_spawn_id exp8 in mi-support.exp:default_mi_gdb_start
>>>> gdbserver-support.exp:gdbserver_start called
>   *** set server_spawn_id in gdbserver-support.exp:gdbserver_start
>   *** set inferior_spawn_id to server_spawn_id exp9 in gdbserver-support.exp.exp:gdbserver_start
>>>> gdbserver-support.exp:gdbserver_start called
>   *** set server_spawn_id in gdbserver-support.exp:gdbserver_start
>   *** set inferior_spawn_id to server_spawn_id exp10 in gdbserver-support.exp.exp:gdbserver_start
>>>> mi-support.exp:mi_uncatched_gdb_exit called
>   *** unset inferior_spawn_id in mi-support.exp:mi_uncatched_gdb_exit
>>>> gdbserver-support.exp:gdb_exit called
>   *** unset server_spawn_id in gdbserver-support.exp:close_gdbserver
>   *** unset inferior_spawn_id in gdbserver-support.exp:close_gdbserver  <--- This is the one that breaks.
> 
> The easy way would be to add a "info exists" check before unsetting it, but I don't know if
> that would only hide a real problem.
> 
> Simon
> 


^ permalink raw reply	[flat|nested] 72+ messages in thread

* [pushed] Fix gdbserver/MI testing regression (was: Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI)
  2016-06-29 10:50     ` Pedro Alves
@ 2016-06-30 11:12       ` Pedro Alves
  2016-06-30 12:10         ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Pedro Alves
  2016-07-04 17:22         ` [pushed] Fix gdbserver/MI testing regression Simon Marchi
  0 siblings, 2 replies; 72+ messages in thread
From: Pedro Alves @ 2016-06-30 11:12 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches

On 06/29/2016 11:50 AM, Pedro Alves wrote:
> On 06/28/2016 09:19 PM, Simon Marchi wrote:
>> I added a few traces to understand what's happening, and it seems that inferior_spawn_id
>> is being unset at two places:

Indeed.

>> The easy way would be to add a "info exists" check before unsetting it, but I don't know if
>> that would only hide a real problem.

I went ahead and pushed the patch below, with takes an even easier route.

I think we'll need to do something better in at least a couple scenarios:

 - If/when gdbserver learns about "set inferior-tty", the separate
   inferior tty spawn id should be used instead of gdbserver's.  gdbserver
   doesn't support that, so in tests that use that (or MI's equivalent),
   inferior output indeed is sent to gdbserver's tty.

 - Tests that disconnect from gdbserver/restart gdb/reconnect to gdbserver
   should end up inferior_spawn_id set to gdbserver's spawn id,
   otherwise tests that rely on inferior I/O, after the reconnect won't work
   properly.  I think there's no such test currently, though, so I'm ignoring
   this for now.

From 038d48680941f014349256aeb7bab14b3f01d58e Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>
Date: Thu, 30 Jun 2016 11:55:22 +0100
Subject: [PATCH] Fix gdbserver/MI testing regression

Commit 51f77c3704a6 ("Add testing infrastruture bits for running with
MI on a separate UI") broke MI testing with native-gdbserver:

 $ make check RUNTESTFLAGS="--target_board=native-gdbserver mi-var-child.exp"
	 ...
 Running .../src/binutils-gdb/gdb/testsuite/gdb.mi/mi-var-child.exp ...
 can't unset "inferior_spawn_id": no such variable
     while executing
 "unset inferior_spawn_id"
     (procedure "close_gdbserver" line 20)
     invoked from within
 "close_gdbserver"
 ...

When testing with gdbserver, gdb_exit is overridden with a special
version that calls close_gdbserver, which clears inferior_spawn_id.
The problem is that the commit mentioned above made
gdb_exit/mi_gdb_exit clear inferior_spawn_id too, and clearing a
non-existing variable is a tcl error.

Since gdb_exit/mi_gdb_exit always clears inferior_spawn_id now, the
fix is simply to stop clearing it in close_gdbserver.

gdb/testsuite/
2016-06-30  Pedro Alves  <palves@redhat.com>

	* lib/gdbserver-support.exp (close_gdbserver, gdb_exit): Don't
	unset inferior_spawn_id.
---
 gdb/testsuite/ChangeLog                 | 5 +++++
 gdb/testsuite/lib/gdbserver-support.exp | 6 ++----
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index ab0d9e6..1362f09 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,10 @@
 2016-06-30  Pedro Alves  <palves@redhat.com>
 
+	* lib/gdbserver-support.exp (close_gdbserver, gdb_exit): Don't
+	unset inferior_spawn_id.
+
+2016-06-30  Pedro Alves  <palves@redhat.com>
+
 	* lib/mi-support.exp (default_mi_gdb_start): Declare global
 	FORCE_SEPARATE_MI_TTY, not SEPARATE_MI_TTY.
 
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
index 951afe5..b792b23 100644
--- a/gdb/testsuite/lib/gdbserver-support.exp
+++ b/gdb/testsuite/lib/gdbserver-support.exp
@@ -324,7 +324,7 @@ proc gdbserver_spawn { child_args } {
 # Close the GDBserver connection.
 
 proc close_gdbserver {} {
-    global server_spawn_id inferior_spawn_id
+    global server_spawn_id
 
     # We can't just call close, because if gdbserver is local then that means
     # that it will get a SIGHUP.  Doing it this way could also allow us to
@@ -340,7 +340,6 @@ proc close_gdbserver {} {
     catch "close -i $server_spawn_id"
     catch "wait -i $server_spawn_id"
     unset server_spawn_id
-    unset inferior_spawn_id
 }
 
 # Hook into GDB exit, and close GDBserver.
@@ -349,7 +348,7 @@ if { [info procs gdbserver_gdb_exit] == "" } {
     rename gdb_exit gdbserver_orig_gdb_exit
 }
 proc gdb_exit {} {
-    global gdb_spawn_id server_spawn_id inferior_spawn_id
+    global gdb_spawn_id server_spawn_id
     global gdb_prompt
     global gdbserver_reconnect_p
 
@@ -376,7 +375,6 @@ proc gdb_exit {} {
 		-i "$server_spawn_id" eof {
 		    wait -i $expect_out(spawn_id)
 		    unset server_spawn_id
-		    unset inferior_spawn_id
 		}
 	    }
 	}
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression)
  2016-06-30 11:12       ` [pushed] Fix gdbserver/MI testing regression (was: Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI) Pedro Alves
@ 2016-06-30 12:10         ` Pedro Alves
  2016-07-04 20:40           ` gdbserver/ada testing broken Simon Marchi
  2016-07-05 16:36           ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Joel Brobecker
  2016-07-04 17:22         ` [pushed] Fix gdbserver/MI testing regression Simon Marchi
  1 sibling, 2 replies; 72+ messages in thread
From: Pedro Alves @ 2016-06-30 12:10 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches, Joel Brobecker

BTW, while testing this, I noticed that all gdb.ada/ tests that build
a binary with the same name as their test directory are broken.
I suspect this is a regression caused by one of the gdb_remote_download,
etc. patches.

For example:

 Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.ada/formatted_ref.exp ...
 PASS: gdb.ada/formatted_ref.exp: compilation formatted_ref.adb
 FAIL: gdb.ada/formatted_ref.exp: print/x s
 FAIL: gdb.ada/formatted_ref.exp: print/x s'access
 FAIL: gdb.ada/formatted_ref.exp: print s.x = 13

gdb.log shows:

 The program is not being run.
 (gdb) file /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref/formatted_ref
 Reading symbols from /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref/formatted_ref...done.
...
 (gdb) spawn ../gdbserver/gdbserver --once :2346 /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref
 Process /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref created; pid = 7553
 Cannot exec /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref: Permission denied.

 Child exited with status 127
 No program to debug

Note how gdb loads:

  .../gdb.ada/formatted_ref/formatted_ref/formatted_ref

while gdbserver tries to load:

  .../gdb.ada/formatted_ref/formatted_ref

... which fails because it's the directory.

This is probably because gdb_remote_download only minds "tail" when
deciding the destination filename:

proc gdb_remote_download {dest fromfile {tofile {}}} {
    # If TOFILE is not given, default to the same filename as FROMFILE.
    if {[string length $tofile] == 0} {
	set tofile [file tail $fromfile]
    }

    if {[is_remote $dest]} {
	# When the DEST is remote, we simply send the file to DEST.
	global cleanfiles

	set destname [remote_download $dest $fromfile $tofile]
	lappend cleanfiles $destname

	return $destname


and then gdbserver-base.exp does:

proc ${board}_download { board host dest } {
    # We pass DEST in standard_output_file, regardless of whether it is absolute
    # or relative, because we don't want the tests to be able to write outside
    # their standard output directory.
    set dest [standard_output_file $dest]

    file copy -force $host $dest

    return $dest
}

Here $dest already exists when we get here -- it's the directory.

I haven't confirmed, just inspected the code.

Not sure exactly what the best fix is.  Maybe simply tweak
the tests to never get into this situation, along with
making standard_ada_testfile issue perror when it happens?

Most tests pass an explicit base_file name to standard_ada_testfile
that avoids the conflict, like:

  gdb.ada/str_ref_cmp.exp:18:standard_ada_testfile foo

Maybe standard_ada_testfile's $base_file parameter should be
defaulted, like:

 -proc standard_ada_testfile {base_file {dir ""}} {
 +proc standard_ada_testfile {{base_file "test"} {dir ""}} {

and then most tests adjusted to not pass an explicit
base_file at all.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm
  2016-05-06 12:35 ` [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
@ 2016-07-01 11:02   ` Thomas Preudhomme
  2016-07-01 12:05     ` [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) (was: Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm) Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Thomas Preudhomme @ 2016-07-01 11:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Hi Pedro,

On Friday 06 May 2016 13:34:54 Pedro Alves wrote:
> I noticed that if we step into an inline function, step_1 never
> reaches proceed, and thus nevers sets the thread's
> tp->control.command_interp.  Because of that,
> should_print_stop_to_console fails to determine that is should print
> stop output to the console.
> 
> The fix is to set the thread's command_interp earlier.  However, I
> realized that we can move that field to the thread_fsm, given that its
> lifetime is exactly the same as thread_fsm.  So the patch plumbs all
> fsms constructors to take the command interp and store it in the
> thread_fsm.
> 
> We can see the fix in action, with e.g., the gdb.opt/inline-cmds.exp
> test, and issuing a step when stopped at line 67:
> 
>  &"s\n"
>  ^running
>  *running,thread-id="all"
>  (gdb)
>  ~"67\t  result = func2 ();\n"
>  *stopped,reason="end-stepping-
> range",frame={addr="0x00000000004004d0",func="main",args=[],file="/home/pedr
> o/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-
> cmds.c",fullname="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-
> cmds.c",line="67"},thread-id="1",stopped-threads="all",core="0"
>  (gdb)
>  s
>  &"s\n"
>  ^running
>  *running,thread-id="all"
>  (gdb)
> + ~"func2 () at /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-
> cmds.c:67\n"
> + ~"67\t  result = func2 ();\n"
>  *stopped,reason="end-stepping-
> range",frame={addr="0x00000000004004d0",func="func2",args=[],file="/home/ped
> ro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-
> cmds.c",fullname="/home/pedro/gdb/mygit/src/gdb/testsuite/gdb.opt/inline-
> cmds.c",line="67"},thread-id="1",stopped-threads="all",core="0"
>  (gdb)
> 
> (The inline-cmds.exp command is adjusted to exercise this.)
> 
> (Due to the follow_fork change, this also fixes "next N" across a fork
> with "set follow-fork child" with "set detach-on-fork on".  Commands
> that rely on internal breakpoints, like "finish" will still require
> more work to migrate breakpoints etc. to the child thread.)

The new tests added by this patch fail for arm-none-eabi targets because -O2 
leads to instructions to be reordered widely. In this case, the instruction 
that follows the first one for line 64 is related to line 70 so the test is 
failing. Shouldn't this test be compiled with -Og and probably also -finline-
small-functions -findirect-inlining -fpartial-inlining which relates to 
inlining and are included in -O2.

Best regards,

Thomas

^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) (was: Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm)
  2016-07-01 11:02   ` Thomas Preudhomme
@ 2016-07-01 12:05     ` Pedro Alves
  2016-07-01 15:24       ` Thomas Preudhomme
  0 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-07-01 12:05 UTC (permalink / raw)
  To: Thomas Preudhomme; +Cc: gdb-patches

On 07/01/2016 12:02 PM, Thomas Preudhomme wrote:

> The new tests added by this patch fail for arm-none-eabi targets because -O2 
> leads to instructions to be reordered widely. In this case, the instruction 
> that follows the first one for line 64 is related to line 70 so the test is 
> failing. Shouldn't this test be compiled with -Og and probably also -finline-
> small-functions -findirect-inlining -fpartial-inlining which relates to 
> inlining and are included in -O2.

Or even just plain -O0.  See the commit log below.  WDYT?

--------------
Subject: [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on
 __attribute__((always_inline))

A test recently added to gdb.opt/inline-cmds.exp fails for
arm-none-eabi targets because -O2 leads to instructions to be
reordered widely.

I guess it might have made sense years ago to enable optimization in
these tests, but I fail to see the need for that nowadays.

Using -O0 while relying on __attribute__((always_inline)), which is
already used in the tests [1] [2], avoids this sort of trouble, while
still exercising the inlining-related use cases that are the focus of
these tests.

I think that nowadays we can safely assume that all compilers we care
about support __attribute__((always_inline)) or similar.

[1] - Except one spot that missed it.

[2] - Note that the .exp files make sure the frames that should have
      been inlined are indeed inlined, with "info frame".

gdb/testsuite/ChangeLog:
2016-07-01  Pedro Alves  <palves@redhat.com>

	* gdb.opt/inline-break.exp: Remove optimize=-O2.
	* gdb.opt/inline-bt.exp: Likewise.
	* gdb.opt/inline-cmds.exp: Remove optimize=-O2 and add
	additional_flags=-Winline.
	* gdb.opt/inline-locals.exp: Likewise.
	* gdb.opt/inline-markers.c (ATTR): Define.
	(inlined_fn): Use it.
---
 gdb/testsuite/gdb.opt/inline-break.exp  | 2 +-
 gdb/testsuite/gdb.opt/inline-bt.exp     | 2 +-
 gdb/testsuite/gdb.opt/inline-cmds.exp   | 2 +-
 gdb/testsuite/gdb.opt/inline-locals.exp | 2 +-
 gdb/testsuite/gdb.opt/inline-markers.c  | 8 +++++++-
 5 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/gdb/testsuite/gdb.opt/inline-break.exp b/gdb/testsuite/gdb.opt/inline-break.exp
index b2aa22e..ac56b04 100644
--- a/gdb/testsuite/gdb.opt/inline-break.exp
+++ b/gdb/testsuite/gdb.opt/inline-break.exp
@@ -20,7 +20,7 @@
 standard_testfile
 
 if { [prepare_for_testing $testfile.exp $testfile $srcfile \
-          {debug optimize=-O2 additional_flags=-Winline}] } {
+          {debug additional_flags=-Winline}] } {
     return -1
 }
 
diff --git a/gdb/testsuite/gdb.opt/inline-bt.exp b/gdb/testsuite/gdb.opt/inline-bt.exp
index 63d76e2..13c6993 100644
--- a/gdb/testsuite/gdb.opt/inline-bt.exp
+++ b/gdb/testsuite/gdb.opt/inline-bt.exp
@@ -17,7 +17,7 @@ standard_testfile .c inline-markers.c
 
 if {[prepare_for_testing $testfile.exp $testfile \
 	 [list $srcfile $srcfile2] \
-	 {debug optimize=-O2 additional_flags=-Winline}]} {
+	 {debug additional_flags=-Winline}]} {
     return -1
 }
 
diff --git a/gdb/testsuite/gdb.opt/inline-cmds.exp b/gdb/testsuite/gdb.opt/inline-cmds.exp
index 684f4dd..6c84848 100644
--- a/gdb/testsuite/gdb.opt/inline-cmds.exp
+++ b/gdb/testsuite/gdb.opt/inline-cmds.exp
@@ -19,7 +19,7 @@ set MIFLAGS "-i=mi"
 standard_testfile .c inline-markers.c
 
 if {[prepare_for_testing $testfile.exp $testfile \
-	 [list $srcfile $srcfile2] {debug optimize=-O2}]} {
+	 [list $srcfile $srcfile2] {debug additional_flags=-Winline}]} {
     return -1
 }
 
diff --git a/gdb/testsuite/gdb.opt/inline-locals.exp b/gdb/testsuite/gdb.opt/inline-locals.exp
index df2253a..36f7ed2 100644
--- a/gdb/testsuite/gdb.opt/inline-locals.exp
+++ b/gdb/testsuite/gdb.opt/inline-locals.exp
@@ -16,7 +16,7 @@
 standard_testfile .c inline-markers.c
 
 if {[prepare_for_testing $testfile.exp $testfile \
-	 [list $srcfile $srcfile2] {debug optimize=-O2}]} {
+	 [list $srcfile $srcfile2] {debug additional_flags=-Winline}]} {
     return -1
 }
 
diff --git a/gdb/testsuite/gdb.opt/inline-markers.c b/gdb/testsuite/gdb.opt/inline-markers.c
index cf92e79..41f8a38 100644
--- a/gdb/testsuite/gdb.opt/inline-markers.c
+++ b/gdb/testsuite/gdb.opt/inline-markers.c
@@ -13,6 +13,12 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#ifdef __GNUC__
+# define ATTR __attribute__((always_inline))
+#else
+# define ATTR
+#endif
+
 extern int x, y;
 extern volatile int z;
 
@@ -26,7 +32,7 @@ void marker(void)
   x += y - z; /* set breakpoint 2 here */
 }
 
-inline void inlined_fn(void)
+inline ATTR void inlined_fn(void)
 {
   x += y + z;
 }
-- 
2.5.5


^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) (was: Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm)
  2016-07-01 12:05     ` [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) (was: Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm) Pedro Alves
@ 2016-07-01 15:24       ` Thomas Preudhomme
  2016-07-15 12:05         ` Thomas Preudhomme
  0 siblings, 1 reply; 72+ messages in thread
From: Thomas Preudhomme @ 2016-07-01 15:24 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Friday 01 July 2016 13:05:35 Pedro Alves wrote:
> On 07/01/2016 12:02 PM, Thomas Preudhomme wrote:
> > The new tests added by this patch fail for arm-none-eabi targets because
> > -O2 leads to instructions to be reordered widely. In this case, the
> > instruction that follows the first one for line 64 is related to line 70
> > so the test is failing. Shouldn't this test be compiled with -Og and
> > probably also -finline- small-functions -findirect-inlining
> > -fpartial-inlining which relates to inlining and are included in -O2.
> 
> Or even just plain -O0.  See the commit log below.  WDYT?

I'm not very familiar with GDB but the description looks great indeed. Thanks!

Best regards,

Thomas

> 
> --------------
> Subject: [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on
>  __attribute__((always_inline))
> 
> A test recently added to gdb.opt/inline-cmds.exp fails for
> arm-none-eabi targets because -O2 leads to instructions to be
> reordered widely.
> 
> I guess it might have made sense years ago to enable optimization in
> these tests, but I fail to see the need for that nowadays.
> 
> Using -O0 while relying on __attribute__((always_inline)), which is
> already used in the tests [1] [2], avoids this sort of trouble, while
> still exercising the inlining-related use cases that are the focus of
> these tests.
> 
> I think that nowadays we can safely assume that all compilers we care
> about support __attribute__((always_inline)) or similar.
> 
> [1] - Except one spot that missed it.
> 
> [2] - Note that the .exp files make sure the frames that should have
>       been inlined are indeed inlined, with "info frame".
> 
> gdb/testsuite/ChangeLog:
> 2016-07-01  Pedro Alves  <palves@redhat.com>
> 
> 	* gdb.opt/inline-break.exp: Remove optimize=-O2.
> 	* gdb.opt/inline-bt.exp: Likewise.
> 	* gdb.opt/inline-cmds.exp: Remove optimize=-O2 and add
> 	additional_flags=-Winline.
> 	* gdb.opt/inline-locals.exp: Likewise.
> 	* gdb.opt/inline-markers.c (ATTR): Define.
> 	(inlined_fn): Use it.
> ---
>  gdb/testsuite/gdb.opt/inline-break.exp  | 2 +-
>  gdb/testsuite/gdb.opt/inline-bt.exp     | 2 +-
>  gdb/testsuite/gdb.opt/inline-cmds.exp   | 2 +-
>  gdb/testsuite/gdb.opt/inline-locals.exp | 2 +-
>  gdb/testsuite/gdb.opt/inline-markers.c  | 8 +++++++-
>  5 files changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/gdb/testsuite/gdb.opt/inline-break.exp
> b/gdb/testsuite/gdb.opt/inline-break.exp index b2aa22e..ac56b04 100644
> --- a/gdb/testsuite/gdb.opt/inline-break.exp
> +++ b/gdb/testsuite/gdb.opt/inline-break.exp
> @@ -20,7 +20,7 @@
>  standard_testfile
> 
>  if { [prepare_for_testing $testfile.exp $testfile $srcfile \
> -          {debug optimize=-O2 additional_flags=-Winline}] } {
> +          {debug additional_flags=-Winline}] } {
>      return -1
>  }
> 
> diff --git a/gdb/testsuite/gdb.opt/inline-bt.exp
> b/gdb/testsuite/gdb.opt/inline-bt.exp index 63d76e2..13c6993 100644
> --- a/gdb/testsuite/gdb.opt/inline-bt.exp
> +++ b/gdb/testsuite/gdb.opt/inline-bt.exp
> @@ -17,7 +17,7 @@ standard_testfile .c inline-markers.c
> 
>  if {[prepare_for_testing $testfile.exp $testfile \
>  	 [list $srcfile $srcfile2] \
> -	 {debug optimize=-O2 additional_flags=-Winline}]} {
> +	 {debug additional_flags=-Winline}]} {
>      return -1
>  }
> 
> diff --git a/gdb/testsuite/gdb.opt/inline-cmds.exp
> b/gdb/testsuite/gdb.opt/inline-cmds.exp index 684f4dd..6c84848 100644
> --- a/gdb/testsuite/gdb.opt/inline-cmds.exp
> +++ b/gdb/testsuite/gdb.opt/inline-cmds.exp
> @@ -19,7 +19,7 @@ set MIFLAGS "-i=mi"
>  standard_testfile .c inline-markers.c
> 
>  if {[prepare_for_testing $testfile.exp $testfile \
> -	 [list $srcfile $srcfile2] {debug optimize=-O2}]} {
> +	 [list $srcfile $srcfile2] {debug additional_flags=-Winline}]} {
>      return -1
>  }
> 
> diff --git a/gdb/testsuite/gdb.opt/inline-locals.exp
> b/gdb/testsuite/gdb.opt/inline-locals.exp index df2253a..36f7ed2 100644
> --- a/gdb/testsuite/gdb.opt/inline-locals.exp
> +++ b/gdb/testsuite/gdb.opt/inline-locals.exp
> @@ -16,7 +16,7 @@
>  standard_testfile .c inline-markers.c
> 
>  if {[prepare_for_testing $testfile.exp $testfile \
> -	 [list $srcfile $srcfile2] {debug optimize=-O2}]} {
> +	 [list $srcfile $srcfile2] {debug additional_flags=-Winline}]} {
>      return -1
>  }
> 
> diff --git a/gdb/testsuite/gdb.opt/inline-markers.c
> b/gdb/testsuite/gdb.opt/inline-markers.c index cf92e79..41f8a38 100644
> --- a/gdb/testsuite/gdb.opt/inline-markers.c
> +++ b/gdb/testsuite/gdb.opt/inline-markers.c
> @@ -13,6 +13,12 @@
>     You should have received a copy of the GNU General Public License
>     along with this program.  If not, see <http://www.gnu.org/licenses/>. 
> */
> 
> +#ifdef __GNUC__
> +# define ATTR __attribute__((always_inline))
> +#else
> +# define ATTR
> +#endif
> +
>  extern int x, y;
>  extern volatile int z;
> 
> @@ -26,7 +32,7 @@ void marker(void)
>    x += y - z; /* set breakpoint 2 here */
>  }
> 
> -inline void inlined_fn(void)
> +inline ATTR void inlined_fn(void)
>  {
>    x += y + z;
>  }

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [pushed] Fix gdbserver/MI testing regression
  2016-06-30 11:12       ` [pushed] Fix gdbserver/MI testing regression (was: Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI) Pedro Alves
  2016-06-30 12:10         ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Pedro Alves
@ 2016-07-04 17:22         ` Simon Marchi
  1 sibling, 0 replies; 72+ messages in thread
From: Simon Marchi @ 2016-07-04 17:22 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 16-06-30 07:12 AM, Pedro Alves wrote:
> On 06/29/2016 11:50 AM, Pedro Alves wrote:
>> On 06/28/2016 09:19 PM, Simon Marchi wrote:
>>> I added a few traces to understand what's happening, and it seems that inferior_spawn_id
>>> is being unset at two places:
> 
> Indeed.
> 
>>> The easy way would be to add a "info exists" check before unsetting it, but I don't know if
>>> that would only hide a real problem.
> 
> I went ahead and pushed the patch below, with takes an even easier route.
> 
> I think we'll need to do something better in at least a couple scenarios:
> 
>  - If/when gdbserver learns about "set inferior-tty", the separate
>    inferior tty spawn id should be used instead of gdbserver's.  gdbserver
>    doesn't support that, so in tests that use that (or MI's equivalent),
>    inferior output indeed is sent to gdbserver's tty.
> 
>  - Tests that disconnect from gdbserver/restart gdb/reconnect to gdbserver
>    should end up inferior_spawn_id set to gdbserver's spawn id,
>    otherwise tests that rely on inferior I/O, after the reconnect won't work
>    properly.  I think there's no such test currently, though, so I'm ignoring
>    this for now.

Thanks!  Your patch fixes the problem I initially encountered.

Simon

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-06-30 12:10         ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Pedro Alves
@ 2016-07-04 20:40           ` Simon Marchi
  2016-07-05 15:28             ` Joel Brobecker
  2016-07-05 16:36           ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Joel Brobecker
  1 sibling, 1 reply; 72+ messages in thread
From: Simon Marchi @ 2016-07-04 20:40 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Joel Brobecker

On 16-06-30 08:10 AM, Pedro Alves wrote:
> BTW, while testing this, I noticed that all gdb.ada/ tests that build
> a binary with the same name as their test directory are broken.
> I suspect this is a regression caused by one of the gdb_remote_download,
> etc. patches.
> 
> For example:
> 
>  Running /home/pedro/gdb/mygit/src/gdb/testsuite/gdb.ada/formatted_ref.exp ...
>  PASS: gdb.ada/formatted_ref.exp: compilation formatted_ref.adb
>  FAIL: gdb.ada/formatted_ref.exp: print/x s
>  FAIL: gdb.ada/formatted_ref.exp: print/x s'access
>  FAIL: gdb.ada/formatted_ref.exp: print s.x = 13
> 
> gdb.log shows:
> 
>  The program is not being run.
>  (gdb) file /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref/formatted_ref
>  Reading symbols from /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref/formatted_ref...done.
> ...
>  (gdb) spawn ../gdbserver/gdbserver --once :2346 /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref
>  Process /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref created; pid = 7553
>  Cannot exec /home/pedro/brno/pedro/gdb/mygit/build/gdb/testsuite/outputs/gdb.ada/formatted_ref/formatted_ref: Permission denied.
> 
>  Child exited with status 127
>  No program to debug
> 
> Note how gdb loads:
> 
>   .../gdb.ada/formatted_ref/formatted_ref/formatted_ref
> 
> while gdbserver tries to load:
> 
>   .../gdb.ada/formatted_ref/formatted_ref
> 
> ... which fails because it's the directory.
> 
> This is probably because gdb_remote_download only minds "tail" when
> deciding the destination filename:
> 
> proc gdb_remote_download {dest fromfile {tofile {}}} {
>     # If TOFILE is not given, default to the same filename as FROMFILE.
>     if {[string length $tofile] == 0} {
> 	set tofile [file tail $fromfile]
>     }
> 
>     if {[is_remote $dest]} {
> 	# When the DEST is remote, we simply send the file to DEST.
> 	global cleanfiles
> 
> 	set destname [remote_download $dest $fromfile $tofile]
> 	lappend cleanfiles $destname
> 
> 	return $destname
> 
> 
> and then gdbserver-base.exp does:
> 
> proc ${board}_download { board host dest } {
>     # We pass DEST in standard_output_file, regardless of whether it is absolute
>     # or relative, because we don't want the tests to be able to write outside
>     # their standard output directory.
>     set dest [standard_output_file $dest]
> 
>     file copy -force $host $dest
> 
>     return $dest
> }
> 
> Here $dest already exists when we get here -- it's the directory.
> 
> I haven't confirmed, just inspected the code.

I think you are right.

> Not sure exactly what the best fix is.  Maybe simply tweak
> the tests to never get into this situation, along with
> making standard_ada_testfile issue perror when it happens?
> 
> Most tests pass an explicit base_file name to standard_ada_testfile
> that avoids the conflict, like:
> 
>   gdb.ada/str_ref_cmp.exp:18:standard_ada_testfile foo
> 
> Maybe standard_ada_testfile's $base_file parameter should be
> defaulted, like:
> 
>  -proc standard_ada_testfile {base_file {dir ""}} {
>  +proc standard_ada_testfile {{base_file "test"} {dir ""}} {
> 
> and then most tests adjusted to not pass an explicit
> base_file at all.
> 
> Thanks,
> Pedro Alves
> 

Is there a reason have a double level of directories named after the test?

outputs
└── gdb.ada
    └── formatted_ref
        └── formatted_ref
            ├── b~formatted_ref.adb
            ├── b~formatted_ref.ads
            ├── b~formatted_ref.ali
            ├── b~formatted_ref.o
            ├── defs.ali
            ├── defs.o
            ├── formatted_ref
            ├── formatted_ref.ali
            └── formatted_ref.o

If we removed the extra "formatted_ref" level, we wouldn't have the problem at all.
The source and destination would become identical when running locally, just like
when testing C/C++.  Or maybe it's needed for some reason in Ada?

I made this patch quickly:
https://github.com/simark/binutils-gdb/commit/d451ff22f1980d4a89c5d6d126bc839734fa393f

A few tests that assume the current directory layout need to be adjusted, but other
than that it looks fine.  I'll clean it up, give it more testing and post it tomorrow,
unless you say it's a wrong approach in the mean time.

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-07-04 20:40           ` gdbserver/ada testing broken Simon Marchi
@ 2016-07-05 15:28             ` Joel Brobecker
  2016-07-05 15:47               ` Joel Brobecker
  0 siblings, 1 reply; 72+ messages in thread
From: Joel Brobecker @ 2016-07-05 15:28 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Pedro Alves, gdb-patches

> Is there a reason have a double level of directories named after the test?
> 
> outputs
> └── gdb.ada
>     └── formatted_ref
>         └── formatted_ref

Initially, I thought this was an obvious mistake. But after further
thought, I think it now expected and done for all testcases, including
the testscases where the main has a name that's different from
the name of the testcase.

I'm looking at Pedro's email, now, as I think the issue is indeed
confined to when testing remotely.

-- 
Joel

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-07-05 15:28             ` Joel Brobecker
@ 2016-07-05 15:47               ` Joel Brobecker
  0 siblings, 0 replies; 72+ messages in thread
From: Joel Brobecker @ 2016-07-05 15:47 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Pedro Alves, gdb-patches

> > Is there a reason have a double level of directories named after the test?
> > 
> > outputs
> > └── gdb.ada
> >     └── formatted_ref
> >         └── formatted_ref
> 
> Initially, I thought this was an obvious mistake. But after further
> thought, I think it now expected and done for all testcases, including
> the testscases where the main has a name that's different from
> the name of the testcase.

When I started writing the email, I meant to give a little more
info than that.

The root "formatted_ref" is because the the .exp name. The second
is because gdb.ada organizes its test programs inside one subdirectory
per testcase, where the subdirectory name is the name of the testcase.
Hence the same second subdirectory, whose name is the same as the
first one.

-- 
Joel

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression)
  2016-06-30 12:10         ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Pedro Alves
  2016-07-04 20:40           ` gdbserver/ada testing broken Simon Marchi
@ 2016-07-05 16:36           ` Joel Brobecker
  2016-07-05 17:19             ` gdbserver/ada testing broken Simon Marchi
  1 sibling, 1 reply; 72+ messages in thread
From: Joel Brobecker @ 2016-07-05 16:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Simon Marchi, gdb-patches

> This is probably because gdb_remote_download only minds "tail" when
> deciding the destination filename:
> 
> proc gdb_remote_download {dest fromfile {tofile {}}} {
>     # If TOFILE is not given, default to the same filename as FROMFILE.
>     if {[string length $tofile] == 0} {
> 	set tofile [file tail $fromfile]
>     }

Looks like this code is indirectly assuming that the code is in the same
directory as the .exp. That's why it can extract the target directory
via a simple "tail".  I tried looking at whether we could make sure
"tofile" was explicitly passed at least for Ada, but it doesn't look
really like an option, as I think this comes from gdb_file_cmd where,
logically, all we care about is which executable to load into GDB.

I am running out of time to investigate this for now, but to me,
thinking this further, I think the most promising avenue is probably
to look at eliminating the subdirectory, since our testing procedure
now creates one per test already. But I'm not sure how this is going
to affect in-tree testing.

-- 
Joel

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-07-05 16:36           ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Joel Brobecker
@ 2016-07-05 17:19             ` Simon Marchi
  2016-07-06 13:23               ` Joel Brobecker
  2016-07-19 17:11               ` Pedro Alves
  0 siblings, 2 replies; 72+ messages in thread
From: Simon Marchi @ 2016-07-05 17:19 UTC (permalink / raw)
  To: Joel Brobecker, Pedro Alves; +Cc: gdb-patches

On 16-07-05 12:36 PM, Joel Brobecker wrote:
>> This is probably because gdb_remote_download only minds "tail" when
>> deciding the destination filename:
>>
>> proc gdb_remote_download {dest fromfile {tofile {}}} {
>>     # If TOFILE is not given, default to the same filename as FROMFILE.
>>     if {[string length $tofile] == 0} {
>> 	set tofile [file tail $fromfile]
>>     }
> 
> Looks like this code is indirectly assuming that the code is in the same
> directory as the .exp. That's why it can extract the target directory
> via a simple "tail".  I tried looking at whether we could make sure
> "tofile" was explicitly passed at least for Ada, but it doesn't look
> really like an option, as I think this comes from gdb_file_cmd where,
> logically, all we care about is which executable to load into GDB.

Hi Joel,

I posted this patch this morning, I should have CC'ed you:
https://sourceware.org/ml/gdb-patches/2016-07/msg00068.html

I think it solves it.

> I am running out of time to investigate this for now, but to me,
> thinking this further, I think the most promising avenue is probably
> to look at eliminating the subdirectory, since our testing procedure
> now creates one per test already. But I'm not sure how this is going
> to affect in-tree testing.

I think it will work regardless of in-tree/out-of-tree, since we always use the
same layout, under the "outputs" directory.  I tested it before sending my patch
and it seemed to work fine.

Simon

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-07-05 17:19             ` gdbserver/ada testing broken Simon Marchi
@ 2016-07-06 13:23               ` Joel Brobecker
  2016-07-06 14:28                 ` Simon Marchi
  2016-07-19 17:11               ` Pedro Alves
  1 sibling, 1 reply; 72+ messages in thread
From: Joel Brobecker @ 2016-07-06 13:23 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Pedro Alves, gdb-patches

Hi Simon,

> I posted this patch this morning, I should have CC'ed you:
> https://sourceware.org/ml/gdb-patches/2016-07/msg00068.html
> 
> I think it solves it.

I think you are right, and in the way that I was leaning towards.

I got confused when I first saw the patch, as the meat of the patch
in lib/ada.exp was kind of obscured because it is at the end after
a number of changes I couldn't really understand (because I hadn't
seen the part in ada.exp).

I didn't think it would be so easy. That looks pretty good to me,
and indeed, now that everything is done in the "outputs" directory,
that should solve the issue of in-tree builds.

Go ahead, and push.
Thanks for the fix!

-- 
Joel

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-07-06 13:23               ` Joel Brobecker
@ 2016-07-06 14:28                 ` Simon Marchi
  0 siblings, 0 replies; 72+ messages in thread
From: Simon Marchi @ 2016-07-06 14:28 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Pedro Alves, gdb-patches

On 16-07-06 09:23 AM, Joel Brobecker wrote:
> Hi Simon,
> 
>> I posted this patch this morning, I should have CC'ed you:
>> https://sourceware.org/ml/gdb-patches/2016-07/msg00068.html
>>
>> I think it solves it.
> 
> I think you are right, and in the way that I was leaning towards.
> 
> I got confused when I first saw the patch, as the meat of the patch
> in lib/ada.exp was kind of obscured because it is at the end after
> a number of changes I couldn't really understand (because I hadn't
> seen the part in ada.exp).
> 
> I didn't think it would be so easy. That looks pretty good to me,
> and indeed, now that everything is done in the "outputs" directory,
> that should solve the issue of in-tree builds.
> 
> Go ahead, and push.
> Thanks for the fix!
> 

Ok, I pushed it.

I also pushed this one to fix an instance I forgot.
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=986cf455bfb25d8696232695fbcc93649c10a523

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) (was: Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm)
  2016-07-01 15:24       ` Thomas Preudhomme
@ 2016-07-15 12:05         ` Thomas Preudhomme
  2016-07-19 17:02           ` [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) Pedro Alves
  0 siblings, 1 reply; 72+ messages in thread
From: Thomas Preudhomme @ 2016-07-15 12:05 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Friday 01 July 2016 16:24:38 Thomas Preudhomme wrote:
> On Friday 01 July 2016 13:05:35 Pedro Alves wrote:
> > On 07/01/2016 12:02 PM, Thomas Preudhomme wrote:
> > > The new tests added by this patch fail for arm-none-eabi targets because
> > > -O2 leads to instructions to be reordered widely. In this case, the
> > > instruction that follows the first one for line 64 is related to line 70
> > > so the test is failing. Shouldn't this test be compiled with -Og and
> > > probably also -finline- small-functions -findirect-inlining
> > > -fpartial-inlining which relates to inlining and are included in -O2.
> > 
> > Or even just plain -O0.  See the commit log below.  WDYT?
> 
> I'm not very familiar with GDB but the description looks great indeed.
> Thanks!

Hi Pedro,

What is the status of that patch?

Best regards,

Thomas

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline))
  2016-07-15 12:05         ` Thomas Preudhomme
@ 2016-07-19 17:02           ` Pedro Alves
  2016-07-20 16:35             ` Thomas Preudhomme
  0 siblings, 1 reply; 72+ messages in thread
From: Pedro Alves @ 2016-07-19 17:02 UTC (permalink / raw)
  To: Thomas Preudhomme; +Cc: gdb-patches

On 07/15/2016 01:05 PM, Thomas Preudhomme wrote:

> Hi Pedro,
> 
> What is the status of that patch?

Sorry, I've been away for a couple weeks.

Seems like no one objected, so I'm putting it in now.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: gdbserver/ada testing broken
  2016-07-05 17:19             ` gdbserver/ada testing broken Simon Marchi
  2016-07-06 13:23               ` Joel Brobecker
@ 2016-07-19 17:11               ` Pedro Alves
  1 sibling, 0 replies; 72+ messages in thread
From: Pedro Alves @ 2016-07-19 17:11 UTC (permalink / raw)
  To: Simon Marchi, Joel Brobecker; +Cc: gdb-patches

On 07/05/2016 06:19 PM, Simon Marchi wrote:

> I think it will work regardless of in-tree/out-of-tree, since we always use the
> same layout, under the "outputs" directory.  I tested it before sending my patch
> and it seemed to work fine.
> 

Thanks for fixing this.  Glad that we could normalize things a
bit more.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline))
  2016-07-19 17:02           ` [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) Pedro Alves
@ 2016-07-20 16:35             ` Thomas Preudhomme
  0 siblings, 0 replies; 72+ messages in thread
From: Thomas Preudhomme @ 2016-07-20 16:35 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tuesday 19 July 2016 18:02:37 Pedro Alves wrote:
> On 07/15/2016 01:05 PM, Thomas Preudhomme wrote:
> > Hi Pedro,
> > 
> > What is the status of that patch?
> 
> Sorry, I've been away for a couple weeks.
> 
> Seems like no one objected, so I'm putting it in now.

Test is now PASSing for us. Thanks!

Best regards,

Thomas

^ permalink raw reply	[flat|nested] 72+ messages in thread

end of thread, other threads:[~2016-07-20 16:35 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-06 12:35 [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves
2016-05-06 12:35 ` [PATCH v3 02/34] [Ada catchpoints] Fix "warning: failed to get exception name: No definition of \"e.full_name\" in current context" Pedro Alves
2016-05-06 12:35 ` [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
2016-07-01 11:02   ` Thomas Preudhomme
2016-07-01 12:05     ` [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) (was: Re: [PATCH v3 24/34] Push thread->control.command_interp to the struct thread_fsm) Pedro Alves
2016-07-01 15:24       ` Thomas Preudhomme
2016-07-15 12:05         ` Thomas Preudhomme
2016-07-19 17:02           ` [PATCH] Build gdb.opt/inline-*.exp tests at -O0, rely on __attribute__((always_inline)) Pedro Alves
2016-07-20 16:35             ` Thomas Preudhomme
2016-05-06 12:35 ` [PATCH v3 03/34] Introduce "struct ui" Pedro Alves
2016-05-06 12:35 ` [PATCH v3 29/34] Add new command to create extra console/mi UI channels Pedro Alves
2016-05-26 18:34   ` Pedro Alves
2016-05-06 12:35 ` [PATCH v3 20/34] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
2016-05-06 12:35 ` [PATCH v3 33/34] Make mi-break.exp always expect breakpoint commands output on the main UI Pedro Alves
2016-05-06 12:35 ` [PATCH v3 14/34] Make command line editing (use of readline) be per UI Pedro Alves
2016-05-06 12:35 ` [PATCH v3 15/34] Always process target events in the main UI Pedro Alves
2016-05-06 12:35 ` [PATCH v3 21/34] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
2016-05-06 12:35 ` [PATCH v3 16/34] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
2016-05-06 12:35 ` [PATCH v3 01/34] Prepare gdb.python/mi-py-events.exp for Python/MI in separate channels Pedro Alves
2016-05-06 12:36 ` [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI Pedro Alves
2016-06-28 20:19   ` Simon Marchi
2016-06-29 10:50     ` Pedro Alves
2016-06-30 11:12       ` [pushed] Fix gdbserver/MI testing regression (was: Re: [PATCH v3 31/34] Add testing infrastruture bits for running with MI on a separate UI) Pedro Alves
2016-06-30 12:10         ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Pedro Alves
2016-07-04 20:40           ` gdbserver/ada testing broken Simon Marchi
2016-07-05 15:28             ` Joel Brobecker
2016-07-05 15:47               ` Joel Brobecker
2016-07-05 16:36           ` gdbserver/ada testing broken (was: Re: [pushed] Fix gdbserver/MI testing regression) Joel Brobecker
2016-07-05 17:19             ` gdbserver/ada testing broken Simon Marchi
2016-07-06 13:23               ` Joel Brobecker
2016-07-06 14:28                 ` Simon Marchi
2016-07-19 17:11               ` Pedro Alves
2016-07-04 17:22         ` [pushed] Fix gdbserver/MI testing regression Simon Marchi
2016-05-06 12:40 ` [PATCH v3 13/34] Make current_ui_out be per UI Pedro Alves
2016-05-06 12:40 ` [PATCH v3 11/34] Make out and error streams " Pedro Alves
2016-05-06 12:40 ` [PATCH v3 23/34] New function should_print_stop_to_console Pedro Alves
2016-05-06 12:41 ` [PATCH v3 06/34] Introduce interpreter factories Pedro Alves
2016-05-18 19:18   ` Simon Marchi
2016-05-26 18:11     ` Pedro Alves
2016-05-18 19:20   ` Simon Marchi
2016-05-26 18:08     ` Pedro Alves
2016-05-06 12:42 ` [PATCH v3 30/34] [DOC] Document support for running interpreters on separate UI channels Pedro Alves
2016-05-06 13:04   ` Eli Zaretskii
2016-05-26 11:11     ` Pedro Alves
2016-06-17 17:24       ` Pedro Alves
2016-06-17 20:02         ` Eli Zaretskii
2016-05-06 12:43 ` [PATCH v3 04/34] Make gdb_stdout&co be per UI Pedro Alves
2016-05-06 12:43 ` [PATCH v3 12/34] Delete def_uiout Pedro Alves
2016-05-06 12:43 ` [PATCH v3 10/34] Make input_fd be per UI Pedro Alves
2016-05-06 12:43 ` [PATCH v3 25/34] Only send sync execution command output to the UI that ran the command Pedro Alves
2016-05-06 12:43 ` [PATCH v3 28/34] Make stdin be per UI Pedro Alves
2016-05-06 12:43 ` [PATCH v3 05/34] Make the interpreters " Pedro Alves
2016-05-18 17:51   ` Simon Marchi
2016-05-26 18:08     ` Pedro Alves
2016-05-06 12:43 ` [PATCH v3 17/34] Introduce display_mi_prompt Pedro Alves
2016-05-06 12:43 ` [PATCH v3 08/34] Always run async signal handlers in the main UI Pedro Alves
2016-05-19 19:28   ` Simon Marchi
2016-05-26 18:13     ` Pedro Alves
2016-05-26 18:15       ` Simon Marchi
2016-05-06 12:43 ` [PATCH v3 07/34] Make the intepreters output to all UIs Pedro Alves
2016-05-19 15:16   ` Simon Marchi
2016-05-26 18:12     ` Pedro Alves
2016-05-06 12:45 ` [PATCH v3 32/34] Send deleted watchpoint-scope " Pedro Alves
2016-05-06 12:45 ` [PATCH v3 22/34] Fix for spurious prompts in secondary UIs Pedro Alves
2016-05-06 12:45 ` [PATCH v3 26/34] Make main_ui be heap allocated Pedro Alves
2016-05-06 12:45 ` [PATCH v3 27/34] Handle UI's terminal closing Pedro Alves
2016-05-06 12:45 ` [PATCH v3 34/34] Always switch fork child to the main UI Pedro Alves
2016-05-06 12:52 ` [PATCH v3 18/34] Make raw_stdout be per MI instance Pedro Alves
2016-05-06 12:53 ` [PATCH v3 09/34] Make instream be per UI Pedro Alves
2016-05-06 12:53 ` [PATCH v3 19/34] Simplify starting the command event loop Pedro Alves
2016-05-26 18:37 ` [PATCH v3 35/34] Add "new-ui console" tests Pedro Alves
2016-06-21  0:23 ` [pushed] Re: [PATCH v3 00/34] Towards great frontend GDB consoles Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).