public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 00/23] Towards great frontend GDB consoles
@ 2016-02-03 16:44 Pedro Alves
  2016-02-03 16:44 ` [PATCH 11/23] Delete def_uiout Pedro Alves
                   ` (23 more replies)
  0 siblings, 24 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 UTC (permalink / raw)
  To: gdb-patches

This series provides a way to for Eclipse and other frontend'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 discussion and
it may be get accepted or the design may need to change.  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
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 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

More details in the last patch of the series (which actually adds the
command).

This still misses ChangeLog entries, some comments, and documentation
changes.  And I haven't thought about tests yet.

Marc asked if he could try the current version of this series, to try
to get support for this on the Eclipse side ASAP, and maybe show it
off at EclipseCon in a few weeks, so here it is, supposedly fully
functional and all cleaned up ready for Eclipse testing, and general
feedback.  :-)

Pedro Alves (23):
  Test issuing a command split in multiple lines with continuation chars
  Command line input handling TLC
  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
  Make instream and serial_stdin be per UI
  Make input_fd be per UI
  Make outstream 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
  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
  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
  Add new command to create extra console/mi UI channels

 gdb/annotate.c                                     |  15 +-
 gdb/breakpoint.c                                   |  21 +-
 gdb/cli/cli-interp.c                               | 253 ++++--
 gdb/cli/cli-interp.h                               |  32 +
 gdb/cli/cli-script.c                               |  27 +-
 gdb/common/buffer.h                                |   8 +
 gdb/compile/compile.c                              |  14 +-
 gdb/defs.h                                         |   2 -
 gdb/event-loop.c                                   |   2 +
 gdb/event-top.c                                    | 731 ++++++++--------
 gdb/event-top.h                                    |  18 +-
 gdb/exceptions.c                                   |   4 +-
 gdb/gdbthread.h                                    |   5 -
 gdb/guile/guile.c                                  |  14 +-
 gdb/guile/scm-ports.c                              |   6 +-
 gdb/inf-loop.c                                     |   2 +-
 gdb/infcall.c                                      |  43 +-
 gdb/infcmd.c                                       | 102 ++-
 gdb/inflow.c                                       |  40 +-
 gdb/infrun.c                                       | 137 ++-
 gdb/infrun.h                                       |  10 +-
 gdb/interps.c                                      | 252 ++++--
 gdb/interps.h                                      |  48 +-
 gdb/linux-nat.c                                    |   2 -
 gdb/main.c                                         |  56 +-
 gdb/mi/mi-interp.c                                 | 946 +++++++++++++--------
 gdb/mi/mi-main.c                                   |   2 +-
 gdb/python/python.c                                |  15 +-
 gdb/remote.c                                       |   2 -
 gdb/target.c                                       |  27 +-
 gdb/terminal.h                                     |   6 +-
 .../gdb.base/command-continuation-char.exp         |  34 +
 gdb/testsuite/gdb.gdb/selftest.exp                 |   4 +
 gdb/thread-fsm.c                                   |  12 +-
 gdb/thread-fsm.h                                   |  23 +-
 gdb/thread.c                                       |   2 +-
 gdb/top.c                                          | 467 +++++-----
 gdb/top.h                                          | 155 +++-
 gdb/tui/tui-interp.c                               | 173 +++-
 gdb/tui/tui-io.c                                   |   4 +-
 gdb/ui-file.c                                      |   4 +-
 gdb/ui-file.h                                      |   4 +-
 gdb/ui-out.c                                       | 184 ----
 gdb/ui-out.h                                       |   3 +-
 gdb/utils.c                                        |   4 +-
 gdb/utils.h                                        |  19 +-
 46 files changed, 2303 insertions(+), 1631 deletions(-)
 create mode 100644 gdb/cli/cli-interp.h
 create mode 100644 gdb/testsuite/gdb.base/command-continuation-char.exp

-- 
1.9.3

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

* [PATCH 03/23] Introduce "struct ui"
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (2 preceding siblings ...)
  2016-02-03 16:44 ` [PATCH 18/23] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:44 ` [PATCH 07/23] Make the intepreters output to all UIs Pedro Alves
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 UTC (permalink / raw)
  To: gdb-patches

I'm aiming 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/event-top.c    | 69 ++++++++++++++++++++++++------------------------------
 gdb/event-top.h    |  2 --
 gdb/mi/mi-interp.c |  5 ++--
 gdb/top.c          | 10 ++++----
 gdb/top.h          | 33 +++++++++++++++++++++++++-
 5 files changed, 71 insertions(+), 48 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 969124e..736a77a 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -76,28 +76,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.  */
 
@@ -179,6 +161,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
@@ -188,18 +172,18 @@ change_line_handler (void)
   if (async_command_editing_p)
     {
       /* Turn on editing by using readline.  */
-      call_readline = rl_callback_read_char_wrapper;
-      input_handler = command_line_handler;
+      ui->call_readline = rl_callback_read_char_wrapper;
+      ui->input_handler = command_line_handler;
     }
   else
     {
       /* Turn off editing by using gdb_readline2.  */
       gdb_rl_callback_handler_remove ();
-      call_readline = gdb_readline_callback_no_editing;
+      ui->call_readline = gdb_readline_callback_no_editing;
 
       /* 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;
     }
 }
 
@@ -232,12 +216,14 @@ gdb_rl_callback_handler_remove (void)
 void
 gdb_rl_callback_handler_install (const char *prompt)
 {
+  struct ui *ui = current_ui;
+
   /* Calling rl_callback_handler_install resets readline's input
      buffer.  Calling this when we were already processing input
      therefore loses input.  */
   gdb_assert (!callback_handler_installed);
 
-  rl_callback_handler_install (prompt, input_handler);
+  rl_callback_handler_install (prompt, ui->input_handler);
   callback_handler_installed = 1;
 }
 
@@ -370,15 +356,15 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-/* Get a pointer to the command line builder.  This is to used to
-   construct a whole line of input from partial input.  */
+static struct ui current_ui_;
+struct ui *current_ui = &current_ui_;
+
+/* Get a pointer to the current UI's line builder.  */
 
 static struct buffer *
 get_line_builder (void)
 {
-  static struct buffer line_builder;
-
-  return &line_builder;
+  return &current_ui->line_builder;
 }
 
 /* When there is an event ready on the stdin file descriptor, instead
@@ -389,6 +375,8 @@ get_line_builder (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"));
@@ -401,7 +389,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);
     }
 }
@@ -653,6 +641,7 @@ command_line_handler (char *rl)
 void
 gdb_readline_callback_no_editing (gdb_client_data client_data)
 {
+  struct ui *ui = current_ui;
   struct buffer *builder = get_line_builder ();
   int c;
   char *r;
@@ -685,7 +674,7 @@ gdb_readline_callback_no_editing (gdb_client_data client_data)
 	      break;
 	    }
 	  xfree (buffer_finish (builder));
-	  (*input_handler) (NULL);
+	  ui->input_handler (NULL);
 	  return;
 	}
 
@@ -703,7 +692,7 @@ gdb_readline_callback_no_editing (gdb_client_data client_data)
   buffer_grow_char (builder, '\0');
 
   r = buffer_finish (builder);
-  (*input_handler) (r);
+  ui->input_handler (r);
 }
 \f
 
@@ -963,6 +952,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
@@ -985,19 +976,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 = rl_callback_read_char_wrapper;
+      ui->call_readline = rl_callback_read_char_wrapper;
     }
   else
     {
       async_command_editing_p = 0;
-      call_readline = gdb_readline_callback_no_editing;
+      ui->call_readline = gdb_readline_callback_no_editing;
     }
   
   /* 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 44e2041..4f89626 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 80c8259..8542a16 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_callback_no_editing;
-  input_handler = mi_execute_command_input_handler;
+  ui->call_readline = gdb_readline_callback_no_editing;
+  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 8e5489e..21fbb0c 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -778,13 +778,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
@@ -810,13 +811,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 d5f1464..66dbd2c 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 line builder.  This is to used to accumulate input until
+     we have a whole command line.  */
+  struct buffer line_builder;
+
+  /* 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;
-- 
1.9.3

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

* [PATCH 18/23] Make gdb_in_secondary_prompt_p() be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
  2016-02-03 16:44 ` [PATCH 11/23] Delete def_uiout Pedro Alves
  2016-02-03 16:44 ` [PATCH 06/23] Introduce interpreter factories Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:44 ` [PATCH 03/23] Introduce "struct ui" Pedro Alves
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 UTC (permalink / raw)
  To: gdb-patches

---
 gdb/top.c        | 15 +++++----------
 gdb/top.h        |  9 +++++++--
 gdb/tui/tui-io.c |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/gdb/top.c b/gdb/top.c
index eefc093..79d5662 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -743,17 +743,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;
 }
 
 
@@ -814,8 +809,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;
@@ -845,7 +840,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 3505319..99a78c2 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -72,6 +72,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
@@ -179,9 +183,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 c00ec46..3d5d327 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -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);
 
-- 
1.9.3

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

* [PATCH 02/23] Command line input handling TLC
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (4 preceding siblings ...)
  2016-02-03 16:44 ` [PATCH 07/23] Make the intepreters output to all UIs Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:44 ` [PATCH 01/23] Test issuing a command split in multiple lines with continuation chars Pedro Alves
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 UTC (permalink / raw)
  To: gdb-patches

The main motivation here was factor out all the globals used by the
line input handling code to a structure, so that we can keep multiple
instances of that.  But I found that this code is a lot messier than
it needs to be, hence this patch cleans things up significantly in the
process as well.
---
 gdb/common/buffer.h |   8 +
 gdb/defs.h          |   2 -
 gdb/event-top.c     | 457 ++++++++++++++++++++++------------------------------
 gdb/event-top.h     |   5 +-
 gdb/inflow.c        |   2 +-
 gdb/inflow.h        |   4 +
 gdb/main.c          |   3 +-
 gdb/mi/mi-interp.c  |   2 +-
 gdb/top.c           | 239 ++++++---------------------
 gdb/top.h           |   7 +-
 10 files changed, 267 insertions(+), 462 deletions(-)

diff --git a/gdb/common/buffer.h b/gdb/common/buffer.h
index 2a47db4..bad2c3a 100644
--- a/gdb/common/buffer.h
+++ b/gdb/common/buffer.h
@@ -31,6 +31,14 @@ struct buffer
    accommodate the new data.  */
 void buffer_grow (struct buffer *buffer, const char *data, size_t size);
 
+/* Append CH to the end of BUFFER.  Grows the buffer to accommodate
+   the new data.  */
+static inline void
+buffer_grow_char (struct buffer *buffer, char c)
+{
+  buffer_grow (buffer, &c, 1);
+}
+
 /* Release any memory held by BUFFER.  */
 void buffer_free (struct buffer *buffer);
 
diff --git a/gdb/defs.h b/gdb/defs.h
index f6ffeac..b94df30 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -285,8 +285,6 @@ extern void print_transfer_performance (struct ui_file *stream,
 
 typedef void initialize_file_ftype (void);
 
-extern char *gdb_readline (const char *);
-
 extern char *gdb_readline_wrapper (const char *);
 
 extern char *command_line_input (const char *, int, char *);
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 2309cce..969124e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -37,6 +37,9 @@
 #include "gdbcmd.h"		/* for dont_repeat() */
 #include "annotate.h"
 #include "maint.h"
+#include "inflow.h"
+#include "serial.h"
+#include "buffer.h"
 
 /* readline include files.  */
 #include "readline/readline.h"
@@ -48,7 +51,6 @@
 static void rl_callback_read_char_wrapper (gdb_client_data client_data);
 static void command_line_handler (char *rl);
 static void change_line_handler (void);
-static void command_handler (char *command);
 static char *top_level_prompt (void);
 
 /* Signal handlers.  */
@@ -107,10 +109,6 @@ void (*call_readline) (gdb_client_data);
    loop as default engine, and event-top.c is merged into top.c.  */
 int async_command_editing_p;
 
-/* This is the annotation suffix that will be used when the
-   annotation_level is 2.  */
-char *async_annotation_suffix;
-
 /* This is used to display the notification of the completion of an
    asynchronous execution command.  */
 int exec_done_display_p = 0;
@@ -143,20 +141,6 @@ static struct async_signal_handler *sigtstp_token;
 #endif
 static struct async_signal_handler *async_sigterm_token;
 
-/* Structure to save a partially entered command.  This is used when
-   the user types '\' at the end of a command line.  This is necessary
-   because each line of input is handled by a different call to
-   command_line_handler, and normally there is no state retained
-   between different calls.  */
-static int more_to_come = 0;
-
-struct readline_input_state
-  {
-    char *linebuffer;
-    char *linebuffer_ptr;
-  }
-readline_input_state;
-
 /* This hook is called by rl_callback_read_char_wrapper after each
    character is processed.  */
 void (*after_char_processing_hook) (void);
@@ -211,7 +195,7 @@ change_line_handler (void)
     {
       /* Turn off editing by using gdb_readline2.  */
       gdb_rl_callback_handler_remove ();
-      call_readline = gdb_readline2;
+      call_readline = gdb_readline_callback_no_editing;
 
       /* Set up the command handler as well, in case we are called as
          first thing from .gdbinit.  */
@@ -363,55 +347,45 @@ display_gdb_prompt (const char *new_prompt)
 static char *
 top_level_prompt (void)
 {
-  char *prefix;
-  char *prompt = NULL;
-  char *suffix;
-  char *composed_prompt;
-  size_t prompt_length;
+  char *prompt;
 
   /* Give observers a chance of changing the prompt.  E.g., the python
      `gdb.prompt_hook' is installed as an observer.  */
   observer_notify_before_prompt (get_prompt ());
 
-  prompt = xstrdup (get_prompt ());
+  prompt = get_prompt ();
 
   if (annotation_level >= 2)
     {
       /* Prefix needs to have new line at end.  */
-      prefix = (char *) alloca (strlen (async_annotation_suffix) + 10);
-      strcpy (prefix, "\n\032\032pre-");
-      strcat (prefix, async_annotation_suffix);
-      strcat (prefix, "\n");
+      const char prefix[] = "\n\032\032pre-prompt\n";
 
       /* Suffix needs to have a new line at end and \032 \032 at
 	 beginning.  */
-      suffix = (char *) alloca (strlen (async_annotation_suffix) + 6);
-      strcpy (suffix, "\n\032\032");
-      strcat (suffix, async_annotation_suffix);
-      strcat (suffix, "\n");
-    }
-  else
-    {
-      prefix = "";
-      suffix = "";
+      const char suffix[] = "\n\032\032prompt\n";
+
+      return concat (prefix, prompt, suffix, NULL);
     }
 
-  prompt_length = strlen (prefix) + strlen (prompt) + strlen (suffix);
-  composed_prompt = (char *) xmalloc (prompt_length + 1);
+  return xstrdup (prompt);
+}
 
-  strcpy (composed_prompt, prefix);
-  strcat (composed_prompt, prompt);
-  strcat (composed_prompt, suffix);
+/* Get a pointer to the command line builder.  This is to used to
+   construct a whole line of input from partial input.  */
 
-  xfree (prompt);
+static struct buffer *
+get_line_builder (void)
+{
+  static struct buffer line_builder;
 
-  return composed_prompt;
+  return &line_builder;
 }
 
-/* When there is an event ready on the stdin file desriptor, instead
+/* When there is an event ready on the stdin file descriptor, instead
    of calling readline directly throught the callback function, or
    instead of calling gdb_readline2, give gdb a chance to detect
    errors and do something.  */
+
 void
 stdin_event_handler (int error, gdb_client_data client_data)
 {
@@ -460,156 +434,120 @@ async_disable_stdin (void)
 }
 \f
 
-/* Handles a gdb command.  This function is called by
-   command_line_handler, which has processed one or more input lines
-   into COMMAND.  */
-/* NOTE: 1999-04-30 This is the asynchronous version of the command_loop
-   function.  The command_loop function will be obsolete when we
-   switch to use the event loop at every execution of gdb.  */
-static void
+/* Handle a gdb command line.  This function is called when
+   handle_line_of_input has concatenated one or more input lines into
+   a whole command.  */
+
+void
 command_handler (char *command)
 {
   struct cleanup *stat_chain;
+  char *c;
 
   clear_quit_flag ();
   if (instream == stdin)
     reinitialize_more_filter ();
 
-  /* If readline returned a NULL command, it means that the connection
-     with the terminal is gone.  This happens at the end of a
-     testsuite run, after Expect has hung up but GDB is still alive.
-     In such a case, we just quit gdb killing the inferior program
-     too.  */
-  if (command == 0)
-    {
-      printf_unfiltered ("quit\n");
-      execute_command ("quit", stdin == instream);
-    }
-
   stat_chain = make_command_stats_cleanup (1);
 
-  execute_command (command, instream == stdin);
+  /* Do not execute commented lines.  */
+  for (c = command; *c == ' ' || *c == '\t'; c++)
+    ;
+  if (c[0] != '#')
+    {
+      execute_command (command, instream == stdin);
 
-  /* Do any commands attached to breakpoint we stopped at.  */
-  bpstat_do_actions ();
+      /* Do any commands attached to breakpoint we stopped at.  */
+      bpstat_do_actions ();
+    }
 
   do_cleanups (stat_chain);
 }
 
-/* Handle a complete line of input.  This is called by the callback
-   mechanism within the readline library.  Deal with incomplete
-   commands as well, by saving the partial input in a global
-   buffer.  */
+/* Append RL to the buffer maintained by CMD_BUILDER.  Returns false if
+   more input is expected (line ends in a backslash), true if we have
+   a whole command line.  Takes ownership of RL.  */
 
-/* NOTE: 1999-04-30 This is the asynchronous version of the
-   command_line_input function; command_line_input will become
-   obsolete once we use the event loop as the default mechanism in
-   GDB.  */
-static void
-command_line_handler (char *rl)
+static char *
+cmd_builder_append (struct buffer *cmd_builder, char *rl)
 {
-  static char *linebuffer = 0;
-  static unsigned linelength = 0;
-  char *p;
-  char *p1;
-  char *nline;
-  int repeat = (instream == stdin);
+  char *cmd;
+  size_t len;
 
-  if (annotation_level > 1 && instream == stdin)
+  len = strlen (rl);
+
+  if (len > 0 && rl[len - 1] == '\\')
     {
-      printf_unfiltered (("\n\032\032post-"));
-      puts_unfiltered (async_annotation_suffix);
-      printf_unfiltered (("\n"));
+      /* Don't copy the backslash and wait for more.  */
+      buffer_grow (cmd_builder, rl, len - 1);
+      cmd = NULL;
     }
-
-  if (linebuffer == 0)
+  else
     {
-      linelength = 80;
-      linebuffer = (char *) xmalloc (linelength);
-      linebuffer[0] = '\0';
+      /* Copy whole line including terminating null, and we're
+	 done.  */
+      buffer_grow (cmd_builder, rl, len + 1);
+      cmd = cmd_builder->buffer;
     }
 
-  p = linebuffer;
+  /* Allocated in readline.  */
+  xfree (rl);
 
-  if (more_to_come)
-    {
-      strcpy (linebuffer, readline_input_state.linebuffer);
-      p = readline_input_state.linebuffer_ptr;
-      xfree (readline_input_state.linebuffer);
-      more_to_come = 0;
-    }
+  return cmd;
+}
 
-#ifdef STOP_SIGNAL
-  if (job_control)
-    signal (STOP_SIGNAL, handle_stop_sig);
-#endif
+/* Handle a line of input coming from readline.
 
-  /* Make sure that all output has been output.  Some machines may let
-     you get away with leaving out some of the gdb_flush, but not
-     all.  */
-  wrap_here ("");
-  gdb_flush (gdb_stdout);
-  gdb_flush (gdb_stderr);
+   If the read line ends with a continuation character (backslash),
+   save the partial input in CMD_BUILDER (except the backslash), and
+   return NULL.  Otherwise, save the partial input and return a
+   pointer to CMD_BUILDER's buffer (null terminated), indicating a
+   whole command line is ready to be executed.
 
-  if (source_file_name != NULL)
-    ++source_line_number;
+   Returns EOF on end of file.
 
-  /* If we are in this case, then command_handler will call quit 
-     and exit from gdb.  */
-  if (!rl || rl == (char *) EOF)
-    {
-      command_handler (0);
-      return;			/* Lint.  */
-    }
-  if (strlen (rl) + 1 + (p - linebuffer) > linelength)
-    {
-      linelength = strlen (rl) + 1 + (p - linebuffer);
-      nline = (char *) xrealloc (linebuffer, linelength);
-      p += nline - linebuffer;
-      linebuffer = nline;
-    }
-  p1 = rl;
-  /* Copy line.  Don't copy null at end.  (Leaves line alone
-     if this was just a newline).  */
-  while (*p1)
-    *p++ = *p1++;
+   If REPEAT, handle command repetitions:
 
-  xfree (rl);			/* Allocated in readline.  */
+     - If the input command line is NOT empty, the command returned is
+       copied into the global 'saved_command_line' var so that it can
+       be repeated later.
 
-  if (p > linebuffer && *(p - 1) == '\\')
-    {
-      *p = '\0';
-      p--;			/* Put on top of '\'.  */
+     - OTOH, if the input command line IS empty, return the previously
+       saved command instead of the empty input line.
+*/
 
-      readline_input_state.linebuffer = xstrdup (linebuffer);
-      readline_input_state.linebuffer_ptr = p;
+char *
+handle_line_of_input (struct buffer *cmd_builder,
+		      char *rl, int repeat, char *annotation_suffix)
+{
+  char *p1;
+  char *cmd;
 
-      /* We will not invoke a execute_command if there is more
-	 input expected to complete the command.  So, we need to
-	 print an empty prompt here.  */
-      more_to_come = 1;
-      display_gdb_prompt ("");
-      return;
-    }
+  if (rl == NULL)
+    return (char *) EOF;
 
-#ifdef STOP_SIGNAL
-  if (job_control)
-    signal (STOP_SIGNAL, SIG_DFL);
-#endif
+  cmd = cmd_builder_append (cmd_builder, rl);
+  if (cmd == NULL)
+    return NULL;
+
+  /* We have a complete command line now.  Prepare for the next
+     command, but leave ownership of memory to the buffer .  */
+  cmd_builder->used_size = 0;
 
-#define SERVER_COMMAND_LENGTH 7
-  server_command =
-    (p - linebuffer > SERVER_COMMAND_LENGTH)
-    && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
-  if (server_command)
+  if (annotation_level > 1 && instream == stdin)
     {
-      /* Note that we don't set `line'.  Between this and the check in
-         dont_repeat, this insures that repeating will still do the
-         right thing.  */
-      *p = '\0';
-      command_handler (linebuffer + SERVER_COMMAND_LENGTH);
-      display_gdb_prompt (0);
-      return;
+      printf_unfiltered (("\n\032\032post-"));
+      puts_unfiltered (annotation_suffix);
+      printf_unfiltered (("\n"));
+    }
+
+#define SERVER_COMMAND_PREFIX "server "
+  if (startswith (cmd, SERVER_COMMAND_PREFIX))
+    {
+      /* Note that we don't set `saved_command_line'.  Between this
+         and the check in dont_repeat, this insures that repeating
+         will still do the right thing.  */
+      return cmd + strlen (SERVER_COMMAND_PREFIX);
     }
 
   /* Do history expansion if that is wished.  */
@@ -619,10 +557,11 @@ command_line_handler (char *rl)
       char *history_value;
       int expanded;
 
-      *p = '\0';		/* Insert null now.  */
-      expanded = history_expand (linebuffer, &history_value);
+      expanded = history_expand (cmd, &history_value);
       if (expanded)
 	{
+	  size_t len;
+
 	  /* Print the changes.  */
 	  printf_unfiltered ("%s\n", history_value);
 
@@ -630,102 +569,93 @@ command_line_handler (char *rl)
 	  if (expanded < 0)
 	    {
 	      xfree (history_value);
-	      return;
+	      return cmd;
 	    }
-	  if (strlen (history_value) > linelength)
-	    {
-	      linelength = strlen (history_value) + 1;
-	      linebuffer = (char *) xrealloc (linebuffer, linelength);
-	    }
-	  strcpy (linebuffer, history_value);
-	  p = linebuffer + strlen (linebuffer);
+
+	  /* history_expand returns an allocated string.  Just replace
+	     our buffer with it.  */
+	  len = strlen (history_value);
+	  xfree (buffer_finish (cmd_builder));
+	  cmd_builder->buffer = history_value;
+	  cmd_builder->buffer_size = len + 1;
+	  cmd = history_value;
 	}
-      xfree (history_value);
     }
 
   /* If we just got an empty line, and that is supposed to repeat the
-     previous command, return the value in the global buffer.  */
-  if (repeat && p == linebuffer && *p != '\\')
-    {
-      command_handler (saved_command_line);
-      display_gdb_prompt (0);
-      return;
-    }
+     previous command, return the previously saved command.  */
+  for (p1 = cmd; *p1 == ' ' || *p1 == '\t'; p1++)
+    ;
+  if (repeat && *p1 == '\0')
+    return saved_command_line;
+
+  /* Add command to history if appropriate.  Note: lines consisting
+     solely of comments are also added to the command history.  This
+     is useful when you type a command, and then realize you don't
+     want to execute it quite yet.  You can comment out the command
+     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 && input_from_terminal_p ())
+    gdb_add_history (cmd);
 
-  for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
-  if (repeat && !*p1)
+  /* Save into global buffer if appropriate.  */
+  if (repeat)
     {
-      command_handler (saved_command_line);
-      display_gdb_prompt (0);
-      return;
+      xfree (saved_command_line);
+      saved_command_line = xstrdup (cmd);
+      return saved_command_line;
     }
+  else
+    return cmd;
+}
 
-  *p = 0;
+/* Handle a complete line of input.  This is called by the callback
+   mechanism within the readline library.  Deal with incomplete
+   commands as well, by saving the partial input in a global
+   buffer.
 
-  /* Add line to history if appropriate.  */
-  if (*linebuffer && input_from_terminal_p ())
-    gdb_add_history (linebuffer);
+   NOTE: This is the asynchronous version of the command_line_input
+   function.  */
 
-  /* Note: lines consisting solely of comments are added to the command
-     history.  This is useful when you type a command, and then
-     realize you don't want to execute it quite yet.  You can comment
-     out the command 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 (*p1 == '#')
-    *p1 = '\0';			/* Found a comment.  */
+void
+command_line_handler (char *rl)
+{
+  struct buffer *cmd_builder = get_line_builder ();
+  char *cmd;
 
-  /* Save into global buffer if appropriate.  */
-  if (repeat)
+  cmd = handle_line_of_input (cmd_builder, rl, instream == stdin, "prompt");
+  if (cmd == (char *) EOF)
     {
-      if (linelength > saved_command_line_size)
-	{
-	  saved_command_line
-	    = (char *) xrealloc (saved_command_line, linelength);
-	  saved_command_line_size = linelength;
-	}
-      strcpy (saved_command_line, linebuffer);
-      if (!more_to_come)
-	{
-	  command_handler (saved_command_line);
-	  display_gdb_prompt (0);
-	}
-      return;
+      /* stdin closed.  The connection with the terminal is gone.
+	 This happens at the end of a testsuite run, after Expect has
+	 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);
+    }
+  else if (cmd == NULL)
+    {
+      /* We don't have a full line yet.  Print an empty prompt.  */
+      display_gdb_prompt ("");
+    }
+  else
+    {
+      command_handler (cmd);
+      display_gdb_prompt (0);
     }
-
-  command_handler (linebuffer);
-  display_gdb_prompt (0);
-  return;
 }
 
 /* Does reading of input from terminal w/o the editing features
-   provided by the readline library.  */
+   provided by the readline library.  Calls the line input handler
+   once we have a whole input line.  */
 
-/* NOTE: 1999-04-30 Asynchronous version of gdb_readline; gdb_readline
-   will become obsolete when the event loop is made the default
-   execution for gdb.  */
 void
-gdb_readline2 (gdb_client_data client_data)
+gdb_readline_callback_no_editing (gdb_client_data client_data)
 {
+  struct buffer *builder = get_line_builder ();
   int c;
-  char *result;
-  int input_index = 0;
-  int result_size = 80;
-  static int done_once = 0;
-
-  /* Unbuffer the input stream, so that, later on, the calls to fgetc
-     fetch only one char at the time from the stream.  The fgetc's will
-     get up to the first newline, but there may be more chars in the
-     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))
-    {
-      setbuf (instream, NULL);
-      done_once = 1;
-    }
-
-  result = (char *) xmalloc (result_size);
+  char *r;
 
   /* We still need the while loop here, even though it would seem
      obvious to invoke gdb_readline2 at every character entered.  If
@@ -736,39 +666,44 @@ gdb_readline2 (gdb_client_data client_data)
 
   while (1)
     {
-      /* 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);
+      /* A non-blocking read.  */
+      c = serial_readchar (stdin_serial, 0);
 
-      if (c == EOF)
+      if (c == SERIAL_ERROR)
 	{
-	  if (input_index > 0)
-	    /* The last line does not end with a newline.  Return it,
-	       and if we are called again fgetc will still return EOF
-	       and we'll return NULL then.  */
-	    break;
-	  xfree (result);
-	  (*input_handler) (0);
+	  /* No chars left.  Go back to event loop.  */
 	  return;
 	}
 
-      if (c == '\n')
+      if (c == SERIAL_EOF)
 	{
-	  if (input_index > 0 && result[input_index - 1] == '\r')
-	    input_index--;
-	  break;
+	  if (builder->used_size > 0)
+	    {
+	      /* The last line does not end with a newline.  Return
+		 it, and if we are called again serial_readchar will
+		 still return EOF and we'll signal error then.  */
+	      break;
+	    }
+	  xfree (buffer_finish (builder));
+	  (*input_handler) (NULL);
+	  return;
 	}
 
-      result[input_index++] = c;
-      while (input_index >= result_size)
+      if (c == '\n')
 	{
-	  result_size *= 2;
-	  result = (char *) xrealloc (result, result_size);
+	  if (builder->used_size > 0
+	      && builder->buffer[builder->used_size - 1] == '\r')
+	    builder->used_size--;
+	  break;
 	}
+
+      buffer_grow_char (builder, c);
     }
 
-  result[input_index++] = '\0';
-  (*input_handler) (result);
+  buffer_grow_char (builder, '\0');
+
+  r = buffer_finish (builder);
+  (*input_handler) (r);
 }
 \f
 
@@ -1055,7 +990,7 @@ gdb_setup_readline (void)
   else
     {
       async_command_editing_p = 0;
-      call_readline = gdb_readline2;
+      call_readline = gdb_readline_callback_no_editing;
     }
   
   /* When readline has read an end-of-line character, it passes the
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 4f20770..44e2041 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -34,6 +34,8 @@ extern void async_init_signals (void);
 extern void set_async_editing_command (char *args, int from_tty,
 				       struct cmd_list_element *c);
 
+extern void command_handler (char *command);
+
 /* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT.  */
 #ifndef STOP_SIGNAL
 #include <signal.h>
@@ -44,7 +46,6 @@ extern void handle_stop_sig (int sig);
 #endif
 extern void handle_sigint (int sig);
 extern void handle_sigterm (int sig);
-extern void gdb_readline2 (void *client_data);
 extern void async_request_quit (void *arg);
 extern void stdin_event_handler (int error, void *client_data);
 extern void async_disable_stdin (void);
@@ -55,13 +56,13 @@ extern void async_enable_stdin (void);
 
 extern int async_command_editing_p;
 extern int exec_done_display_p;
-extern char *async_annotation_suffix;
 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;
+extern void gdb_readline_callback_no_editing (void *client_data);
 
 /* Wrappers for rl_callback_handler_remove and
    rl_callback_handler_install that keep track of whether the callback
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 4c80dbd..4ccd806 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -48,7 +48,7 @@ static void child_terminal_ours_1 (int);
 \f
 /* Record terminal status separately for debugger and inferior.  */
 
-static struct serial *stdin_serial;
+struct serial *stdin_serial;
 
 /* Terminal related info we need to keep track of.  Each inferior
    holds an instance of this structure --- we save it whenever the
diff --git a/gdb/inflow.h b/gdb/inflow.h
index 0d0242e..1c2278e 100644
--- a/gdb/inflow.h
+++ b/gdb/inflow.h
@@ -33,4 +33,8 @@
 extern PROCESS_GROUP_TYPE inferior_process_group (void);
 #endif
 
+/* The serial object that wraps stdin.  */
+
+extern struct serial *stdin_serial;
+
 #endif /* inflow.h */
diff --git a/gdb/main.c b/gdb/main.c
index a338b90..93ed98f 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -506,8 +506,7 @@ captured_main (void *data)
   ndir = 0;
 
   clear_quit_flag ();
-  saved_command_line = (char *) xmalloc (saved_command_line_size);
-  saved_command_line[0] = '\0';
+  saved_command_line = (char *) xstrdup ("");
   instream = stdin;
 
 #ifdef __MINGW32__
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 7f42367..80c8259 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -181,7 +181,7 @@ mi_interpreter_resume (void *data)
 
   /* These overwrite some of the initialization done in
      _intialize_event_loop.  */
-  call_readline = gdb_readline2;
+  call_readline = gdb_readline_callback_no_editing;
   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
diff --git a/gdb/top.c b/gdb/top.c
index ed200ba..8e5489e 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -67,6 +67,7 @@
 #include "cli-out.h"
 #include "tracepoint.h"
 #include "inf-loop.h"
+#include "buffer.h"
 
 #if defined(TUI)
 # include "tui/tui.h"
@@ -124,17 +125,9 @@ char *current_directory;
 /* The directory name is actually stored here (usually).  */
 char gdb_dirbuf[1024];
 
-/* Function to call before reading a command, if nonzero.
-   The function receives two args: an input stream,
-   and a prompt string.  */
-
-void (*window_hook) (FILE *, char *);
-
-/* Buffer used for reading command lines, and the size
-   allocated for it so far.  */
-
+/* The last command line executed on the console.  Used for command
+   repetitions.  */
 char *saved_command_line;
-int saved_command_line_size = 100;
 
 /* Nonzero if the current command is modified by "server ".  This
    affects things like recording into the command history, commands
@@ -540,40 +533,17 @@ execute_command_to_string (char *p, int from_tty)
 void
 command_loop (void)
 {
-  struct cleanup *old_chain;
-  char *command;
-
   while (instream && !feof (instream))
     {
-      if (window_hook && instream == stdin)
-	(*window_hook) (instream, get_prompt ());
-
-      clear_quit_flag ();
-      if (instream == stdin)
-	reinitialize_more_filter ();
-      old_chain = make_cleanup (null_cleanup, 0);
+      char *command;
 
       /* Get a command-line.  This calls the readline package.  */
       command = command_line_input (instream == stdin ?
 				    get_prompt () : (char *) NULL,
 				    instream == stdin, "prompt");
-      if (command == 0)
-	{
-	  do_cleanups (old_chain);
-	  return;
-	}
-
-      make_command_stats_cleanup (1);
-
-      /* Do not execute commented lines.  */
-      if (command[0] != '#')
-	{
-	  execute_command (command, instream == stdin);
-
-	  /* Do any commands attached to breakpoint we are stopped at.  */
-	  bpstat_do_actions ();
-	}
-      do_cleanups (old_chain);
+      if (command == NULL)
+	return;
+      command_handler (command);
     }
 }
 \f
@@ -612,64 +582,60 @@ prevent_dont_repeat (void)
 \f
 /* Read a line from the stream "instream" without command line editing.
 
-   It prints PROMPT_ARG once at the start.
+   It prints PROMPT once at the start.
    Action is compatible with "readline", e.g. space for the result is
    malloc'd and should be freed by the caller.
 
    A NULL return means end of file.  */
-char *
-gdb_readline (const char *prompt_arg)
+
+static char *
+gdb_readline_no_editing (const char *prompt)
 {
-  int c;
-  char *result;
-  int input_index = 0;
-  int result_size = 80;
+  struct buffer line_builder;
+
+  buffer_init (&line_builder);
 
-  if (prompt_arg)
+  if (prompt != NULL)
     {
       /* Don't use a _filtered function here.  It causes the assumed
          character position to be off, since the newline we read from
          the user is not accounted for.  */
-      fputs_unfiltered (prompt_arg, gdb_stdout);
+      fputs_unfiltered (prompt, gdb_stdout);
       gdb_flush (gdb_stdout);
     }
 
-  result = (char *) xmalloc (result_size);
-
   while (1)
     {
+      int c;
+
       /* 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);
 
       if (c == EOF)
 	{
-	  if (input_index > 0)
+	  if (line_builder.used_size > 0)
 	    /* The last line does not end with a newline.  Return it, and
 	       if we are called again fgetc will still return EOF and
 	       we'll return NULL then.  */
 	    break;
-	  xfree (result);
+	  xfree (buffer_finish (&line_builder));
 	  return NULL;
 	}
 
       if (c == '\n')
 	{
-	  if (input_index > 0 && result[input_index - 1] == '\r')
-	    input_index--;
+	  if (line_builder.used_size > 0
+	      && line_builder.buffer[line_builder.used_size - 1] == '\r')
+	    line_builder.used_size--;
 	  break;
 	}
 
-      result[input_index++] = c;
-      while (input_index >= result_size)
-	{
-	  result_size *= 2;
-	  result = (char *) xrealloc (result, result_size);
-	}
+      buffer_grow_char (&line_builder, c);
     }
 
-  result[input_index++] = '\0';
-  return result;
+  buffer_grow_char (&line_builder, '\0');
+  return buffer_finish (&line_builder);
 }
 
 /* Variables which control command line editing and history
@@ -1030,32 +996,28 @@ gdb_safe_append_history (void)
   do_cleanups (old_chain);
 }
 
-/* Read one line from the command input stream `instream'
-   into the local static buffer `linebuffer' (whose current length
-   is `linelength').
-   The buffer is made bigger as necessary.
-   Returns the address of the start of the line.
+/* Read one line from the command input stream `instream' into a local
+   static buffer.  The buffer is made bigger as necessary.  Returns
+   the address of the start of the line.
 
    NULL is returned for end of file.
 
-   *If* the instream == stdin & stdin is a terminal, the line read
-   is copied into the file line saver (global var char *line,
-   length linesize) so that it can be duplicated.
+   *If* the instream == stdin & stdin is a terminal, the line read is
+   copied into the global 'saved_command_line' so that it can be
+   repeated.
 
-   This routine either uses fancy command line editing or
-   simple input as the user has requested.  */
+   This routine either uses fancy command line editing or simple input
+   as the user has requested.  */
 
 char *
 command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 {
-  static char *linebuffer = 0;
-  static unsigned linelength = 0;
+  static struct buffer builder;
   const char *prompt = prompt_arg;
-  char *p;
-  char *p1;
-  char *rl;
-  char *nline;
-  char got_eof = 0;
+  char *cmd;
+
+  /* Starting a new command line.  */
+  builder.used_size = 0;
 
   /* The annotation suffix must be non-NULL.  */
   if (annotation_suffix == NULL)
@@ -1079,14 +1041,6 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
       prompt = local_prompt;
     }
 
-  if (linebuffer == 0)
-    {
-      linelength = 80;
-      linebuffer = (char *) xmalloc (linelength);
-    }
-
-  p = linebuffer;
-
   /* Control-C quits instantly if typed while in this loop
      since it should not wait until the user types a newline.  */
   immediate_quit++;
@@ -1098,6 +1052,8 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 
   while (1)
     {
+      char *rl;
+
       /* Make sure that all output has been output.  Some machines may
          let you get away with leaving out some of the gdb_flush, but
          not all.  */
@@ -1126,40 +1082,18 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 	}
       else
 	{
-	  rl = gdb_readline (prompt);
+	  rl = gdb_readline_no_editing (prompt);
 	}
 
-      if (annotation_level > 1 && instream == stdin)
+      cmd = handle_line_of_input (&builder, rl, repeat, annotation_suffix);
+      if (cmd == (char *) EOF)
 	{
-	  puts_unfiltered ("\n\032\032post-");
-	  puts_unfiltered (annotation_suffix);
-	  puts_unfiltered ("\n");
-	}
-
-      if (!rl || rl == (char *) EOF)
-	{
-	  got_eof = 1;
+	  cmd = NULL;
 	  break;
 	}
-      if (strlen (rl) + 1 + (p - linebuffer) > linelength)
-	{
-	  linelength = strlen (rl) + 1 + (p - linebuffer);
-	  nline = (char *) xrealloc (linebuffer, linelength);
-	  p += nline - linebuffer;
-	  linebuffer = nline;
-	}
-      p1 = rl;
-      /* Copy line.  Don't copy null at end.  (Leaves line alone
-         if this was just a newline).  */
-      while (*p1)
-	*p++ = *p1++;
-
-      xfree (rl);		/* Allocated in readline.  */
-
-      if (p == linebuffer || *(p - 1) != '\\')
+      if (cmd != NULL)
 	break;
 
-      p--;			/* Put on top of '\'.  */
       prompt = NULL;
     }
 
@@ -1169,82 +1103,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 #endif
   immediate_quit--;
 
-  if (got_eof)
-    return NULL;
-
-#define SERVER_COMMAND_LENGTH 7
-  server_command =
-    (p - linebuffer > SERVER_COMMAND_LENGTH)
-    && strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
-  if (server_command)
-    {
-      /* Note that we don't set `line'.  Between this and the check in
-         dont_repeat, this insures that repeating will still do the
-         right thing.  */
-      *p = '\0';
-      return linebuffer + SERVER_COMMAND_LENGTH;
-    }
-
-  /* Do history expansion if that is wished.  */
-  if (history_expansion_p && instream == stdin
-      && ISATTY (instream))
-    {
-      char *history_value;
-      int expanded;
-
-      *p = '\0';		/* Insert null now.  */
-      expanded = history_expand (linebuffer, &history_value);
-      if (expanded)
-	{
-	  /* Print the changes.  */
-	  printf_unfiltered ("%s\n", history_value);
-
-	  /* If there was an error, call this function again.  */
-	  if (expanded < 0)
-	    {
-	      xfree (history_value);
-	      return command_line_input (prompt, repeat,
-					 annotation_suffix);
-	    }
-	  if (strlen (history_value) > linelength)
-	    {
-	      linelength = strlen (history_value) + 1;
-	      linebuffer = (char *) xrealloc (linebuffer, linelength);
-	    }
-	  strcpy (linebuffer, history_value);
-	  p = linebuffer + strlen (linebuffer);
-	}
-      xfree (history_value);
-    }
-
-  /* If we just got an empty line, and that is supposed to repeat the
-     previous command, return the value in the global buffer.  */
-  if (repeat && p == linebuffer)
-    return saved_command_line;
-  for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
-  if (repeat && !*p1)
-    return saved_command_line;
-
-  *p = 0;
-
-  /* Add line to history if appropriate.  */
-  if (*linebuffer && input_from_terminal_p ())
-    gdb_add_history (linebuffer);
-
-  /* Save into global buffer if appropriate.  */
-  if (repeat)
-    {
-      if (linelength > saved_command_line_size)
-	{
-	  saved_command_line
-	    = (char *) xrealloc (saved_command_line, linelength);
-	  saved_command_line_size = linelength;
-	}
-      strcpy (saved_command_line, linebuffer);
-      return saved_command_line;
-    }
-
-  return linebuffer;
+  return cmd;
 }
 \f
 /* Print the GDB banner.  */
@@ -1906,10 +1765,6 @@ init_main (void)
      the DEFAULT_PROMPT is.  */
   set_prompt (DEFAULT_PROMPT);
 
-  /* Set things up for annotation_level > 1, if the user ever decides
-     to use it.  */
-  async_annotation_suffix = "prompt";
-
   /* Set the important stuff up for command editing.  */
   command_editing_p = 1;
   history_expansion_p = 0;
diff --git a/gdb/top.h b/gdb/top.h
index c450c6e..d5f1464 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -20,9 +20,10 @@
 #ifndef TOP_H
 #define TOP_H
 
+struct buffer;
+
 /* From top.c.  */
 extern char *saved_command_line;
-extern int saved_command_line_size;
 extern FILE *instream;
 extern int in_user_command;
 extern int confirm;
@@ -98,4 +99,8 @@ extern void set_verbose (char *, int, struct cmd_list_element *);
 
 extern void do_restore_instream_cleanup (void *stream);
 
+extern char *handle_line_of_input (struct buffer *builder,
+				   char *rl, int repeat,
+				   char *annotation_suffix);
+
 #endif
-- 
1.9.3

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

* [PATCH 06/23] Introduce interpreter factories
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
  2016-02-03 16:44 ` [PATCH 11/23] Delete def_uiout Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:44 ` [PATCH 18/23] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 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.

An alternative method I haven't tried would be to always create all
interpreters whenever a new UI instance is allocated.

I absolutely needed the lazy method in an earlier prototype of this
patch set, but it's not a requirement anymore.  Doesn't hurt though.
---
 gdb/cli/cli-interp.c | 83 +++++++++++++++++++++++++++++++-------------------
 gdb/interps.c        | 86 ++++++++++++++++++++++++++++++++++++++++++----------
 gdb/interps.h        | 11 ++++++-
 gdb/mi/mi-interp.c   | 36 +++++++++++++---------
 gdb/tui/tui-interp.c | 34 +++++++++++++--------
 5 files changed, 173 insertions(+), 77 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index dfbd808..bd50af7 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,30 @@ 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;
+}
+
+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 */
+};
+
+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 +264,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 945b830..6626b4f 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -89,18 +89,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;
@@ -111,6 +113,32 @@ interp_new (const char *name, const struct interp_procs *procs)
   return new_interp;
 }
 
+struct interp_factory
+{
+  /* This is the name in "-i=" and set interpreter.  */
+  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);
+
+static VEC(interp_factory_p) *interpreter_factories = NULL;
+
+void
+interp_factory_register (const char *name, interp_factory_func func)
+{
+  struct interp_factory *f = XNEW (struct interp_factory);
+
+  f->name = name;
+  f->func = func;
+
+  /* FIXME: assert that no factory for NAME is already registered.  */
+  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
@@ -118,7 +146,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;
@@ -217,18 +245,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)
@@ -240,6 +265,35 @@ interp_lookup (const char *name)
   return NULL;
 }
 
+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 *
@@ -467,15 +521,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..f80e563 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -24,6 +24,13 @@
 
 struct ui_out;
 struct interp;
+struct ui;
+
+typedef struct interp *(*interp_factory_func) (const char *interp,
+					       struct ui *ui);
+
+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,7 +71,9 @@ 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);
 extern struct interp *interp_lookup (const char *name);
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 8542a16..9e6f5e4 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -1134,25 +1134,31 @@ mi_set_logging (struct interp *interp, int start_log,
   return 1;
 }
 
+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 */
+};
+
+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..c7910bc 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,30 @@ tui_exec (void *data, const char *command_str)
   internal_error (__FILE__, __LINE__, _("tui_exec called"));
 }
 
+static const struct interp_procs tui_interp_procs = {
+  tui_init,
+  tui_resume,
+  tui_suspend,
+  tui_exec,
+  tui_ui_out,
+  NULL,
+  cli_command_loop
+};
+
+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;
 
-- 
1.9.3

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

* [PATCH 11/23] Delete def_uiout
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:44 ` [PATCH 06/23] Introduce interpreter factories Pedro Alves
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 UTC (permalink / raw)
  To: gdb-patches

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

I noticed that since we create a replacement uiout early on, as soon
as we create the interpreter, that 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/ui-out.c | 181 +----------------------------------------------------------
 1 file changed, 1 insertion(+), 180 deletions(-)

diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index aa6d6fe..7f48d80 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -153,84 +153,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.  */
 
@@ -658,111 +584,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
-- 
1.9.3

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

* [PATCH 07/23] Make the intepreters output to all UIs
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (3 preceding siblings ...)
  2016-02-03 16:44 ` [PATCH 03/23] Introduce "struct ui" Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:44 ` [PATCH 02/23] Command line input handling TLC Pedro Alves
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 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/cli/cli-interp.c | 129 +++++++--
 gdb/event-top.c      |  40 ++-
 gdb/mi/mi-interp.c   | 806 ++++++++++++++++++++++++++++++++-------------------
 gdb/top.h            |  20 ++
 gdb/tui/tui-interp.c | 129 +++++++--
 5 files changed, 767 insertions(+), 357 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index bd50af7..f994d47 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -33,8 +33,13 @@ struct cli_interp
   struct ui_out *cli_uiout;
 };
 
-/* The interpreter for the console interpreter.  */
-static struct interp *cli_interp;
+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 +55,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 +74,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 +92,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 +110,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 +128,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 +146,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 +164,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 +177,17 @@ cli_on_sync_execution_done (void)
 static void
 cli_on_command_error (void)
 {
-  if (!interp_quiet_p (cli_interp))
-    display_gdb_prompt (NULL);
+  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;
+
+      display_gdb_prompt (NULL);
+    }
 }
 
 /* These implement the cli out interpreter: */
@@ -125,19 +195,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);
 }
 
@@ -265,4 +322,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 736a77a..3dc95ab 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -356,8 +356,44 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-static struct ui current_ui_;
-struct ui *current_ui = &current_ui_;
+static struct ui main_ui_;
+
+struct ui *current_ui = &main_ui_;
+struct ui *ui_list = &main_ui_;
+
+static void
+restore_ui_cleanup (void *data)
+{
+  current_ui = (struct ui *) data;
+}
+
+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);
+}
+
+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;
+    }
+}
+
+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 builder.  */
 
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 9e6f5e4..872c201 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -88,6 +88,14 @@ static void mi_on_sync_execution_done (void);
 
 static int report_initial_inferior (struct inferior *inf, void *closure);
 
+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 +135,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 +288,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,38 +339,47 @@ 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 switch_thru_all_uis state;
 
-  gdb_assert (inf);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  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;
+
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-created,id=\"%d\",group-id=\"i%d\"",
+			  t->global_num, t->inf->num);
+      gdb_flush (mi->event_channel);
+    }
 }
 
 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 ();
-  fprintf_unfiltered (mi->event_channel, 
-		      "thread-exited,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 ();
+      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);
+    }
 }
 
 /* Emit notification on changing the state of record.  */
@@ -395,97 +387,132 @@ 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 switch_thru_all_uis state;
 
-  fprintf_unfiltered (mi->event_channel,  "record-%s,thread-group=\"i%d\"",
-		      started ? "started" : "stopped", inferior->num);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  gdb_flush (mi->event_channel);
+      if (mi == NULL)
+	continue;
+
+      fprintf_unfiltered (mi->event_channel,  "record-%s,thread-group=\"i%d\"",
+			  started ? "started" : "stopped", inferior->num);
+
+      gdb_flush (mi->event_channel);
+    }
 }
 
 static void
 mi_inferior_added (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
+  struct switch_thru_all_uis state;
 
-  target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel,
-		      "thread-group-added,id=\"i%d\"",
-		      inf->num);
-  gdb_flush (mi->event_channel);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *interp;
+      struct mi_interp *mi;
+
+      /* We'll be called once for the initial inferior, before the top
+	 level interpreter is set.  */
+      interp = top_level_interpreter ();
+      if (interp == NULL)
+	continue;
+
+      mi = as_mi_interp (interp);
+      if (mi == NULL)
+	continue;
+
+      target_terminal_ours ();
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-group-added,id=\"i%d\"",
+			  inf->num);
+      gdb_flush (mi->event_channel);
+    }
 }
 
 static void
 mi_inferior_appeared (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
+  struct switch_thru_all_uis state;
 
-  target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel,
-		      "thread-group-started,id=\"i%d\",pid=\"%d\"",
-		      inf->num, inf->pid);
-  gdb_flush (mi->event_channel);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+
+      if (mi == NULL)
+	continue;
+
+      target_terminal_ours ();
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-group-started,id=\"i%d\",pid=\"%d\"",
+			  inf->num, inf->pid);
+      gdb_flush (mi->event_channel);
+    }
 }
 
 static void
 mi_inferior_exit (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
+  struct switch_thru_all_uis state;
 
-  target_terminal_ours ();
-  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);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  gdb_flush (mi->event_channel);  
+      if (mi == NULL)
+	continue;
+
+      target_terminal_ours ();
+      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);
+    }
 }
 
 static void
 mi_inferior_removed (struct inferior *inf)
 {
-  struct mi_interp *mi = (struct mi_interp *) top_level_interpreter_data ();
+  struct switch_thru_all_uis state;
 
-  target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel,
-		      "thread-group-removed,id=\"i%d\"",
-		      inf->num);
-  gdb_flush (mi->event_channel);
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+
+      if (mi == NULL)
+	continue;
+
+      target_terminal_ours ();
+      fprintf_unfiltered (mi->event_channel,
+			  "thread-group-removed,id=\"i%d\"",
+			  inf->num);
+      gdb_flush (mi->event_channel);
+    }
 }
 
 /* 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;
 }
 
@@ -498,13 +525,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.  */
@@ -512,13 +544,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 ();
 
-  print_end_stepping_range_reason (mi->mi_uiout);
-  print_end_stepping_range_reason (mi->cli_uiout);
+      if (mi == NULL)
+	continue;
+
+      print_end_stepping_range_reason (mi->mi_uiout);
+      print_end_stepping_range_reason (mi->cli_uiout);
+    }
 }
 
 /* Observer for the signal_exited notification.  */
@@ -526,13 +563,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.  */
@@ -540,13 +582,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 ();
 
-  print_exited_reason (mi->mi_uiout, exitstatus);
-  print_exited_reason (mi->cli_uiout, exitstatus);
+      if (mi == NULL)
+	continue;
+
+      print_exited_reason (mi->mi_uiout, exitstatus);
+      print_exited_reason (mi->cli_uiout, exitstatus);
+    }
 }
 
 /* Observer for the no_history notification.  */
@@ -554,17 +601,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 ();
 
-  print_no_history_reason (mi->mi_uiout);
-  print_no_history_reason (mi->cli_uiout);
+      if (mi == NULL)
+	continue;
+
+      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,
@@ -645,6 +697,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.  */
@@ -675,21 +741,29 @@ 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 switch_thru_all_uis state;
 
   if (mi_suppress_notification.traceframe)
     return;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  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);
+      target_terminal_ours ();
+
+      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);
+    }
 }
 
 /* Emit notification on creating a trace state variable.  */
@@ -697,15 +771,23 @@ 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 switch_thru_all_uis state;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  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);
+      target_terminal_ours ();
+
+      fprintf_unfiltered (mi->event_channel, "tsv-created,"
+			  "name=\"%s\",initial=\"%s\"\n",
+			  tsv->name, plongest (tsv->initial_value));
+
+      gdb_flush (mi->event_channel);
+    }
 }
 
 /* Emit notification on deleting a trace state variable.  */
@@ -713,17 +795,25 @@ 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 switch_thru_all_uis state;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  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);
+      target_terminal_ours ();
+
+      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);
+    }
 }
 
 /* Emit notification on modifying a trace state variable.  */
@@ -731,25 +821,35 @@ 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 switch_thru_all_uis state;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
 
-  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));
+      target_terminal_ours ();
 
-  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);
+
+      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);
+    }
 }
 
 /* Emit notification about a created breakpoint.  */
@@ -757,8 +857,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 switch_thru_all_uis state;
 
   if (mi_suppress_notification.breakpoint)
     return;
@@ -766,29 +865,40 @@ mi_breakpoint_created (struct breakpoint *b)
   if (b->number <= 0)
     return;
 
-  target_terminal_ours ();
-  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;
+
+      if (mi == NULL)
+	continue;
+
+      mi_uiout = interp_ui_out (top_level_interpreter ());
+
+      target_terminal_ours ();
+      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);
+    }
 }
 
 /* Emit notification about deleted breakpoint.  */
@@ -796,7 +906,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 switch_thru_all_uis state;
 
   if (mi_suppress_notification.breakpoint)
     return;
@@ -804,12 +914,20 @@ mi_breakpoint_deleted (struct breakpoint *b)
   if (b->number <= 0)
     return;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
 
-  fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"",
-		      b->number);
+      if (mi == NULL)
+	continue;
 
-  gdb_flush (mi->event_channel);
+      target_terminal_ours ();
+
+      fprintf_unfiltered (mi->event_channel, "breakpoint-deleted,id=\"%d\"",
+			  b->number);
+
+      gdb_flush (mi->event_channel);
+    }
 }
 
 /* Emit notification about modified breakpoint.  */
@@ -817,8 +935,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 switch_thru_all_uis state;
 
   if (mi_suppress_notification.breakpoint)
     return;
@@ -826,40 +943,57 @@ mi_breakpoint_modified (struct breakpoint *b)
   if (b->number <= 0)
     return;
 
-  target_terminal_ours ();
-  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
-    {
-      gdb_breakpoint_query (mi_uiout, b->number, NULL);
-    }
-  CATCH (e, RETURN_MASK_ERROR)
+  SWITCH_THRU_ALL_UIS (state)
     {
-    }
-  END_CATCH
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+
+      if (mi == NULL)
+	continue;
+
+      target_terminal_ours ();
+      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);
+    }
 }
 
 static int
 mi_output_running_pid (struct thread_info *info, void *arg)
 {
   ptid_t *ptid = (ptid_t *) arg;
+  struct switch_thru_all_uis state;
+
+  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);
+      if (ptid_get_pid (*ptid) == ptid_get_pid (info->ptid))
+	fprintf_unfiltered (raw_stdout,
+			    "*running,thread-id=\"%d\"\n",
+			    info->global_num);
+    }
 
   return 0;
 }
@@ -877,19 +1011,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,
@@ -944,54 +1067,102 @@ 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 ());
-
-  target_terminal_ours ();
+  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 ());
+
+      if (mi == NULL)
+	continue;
+
+      mi_on_resume_1 (ptid);
     }
+}
 
-  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;
+
+      if (mi == NULL)
+	continue;
+
+      uiout = interp_ui_out (top_level_interpreter ());
+
+      target_terminal_ours ();
+
+      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);
+    }
 }
 
 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 switch_thru_all_uis state;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *uiout;
 
-  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);
-    }
+      target_terminal_ours ();
 
-  ui_out_redirect (uiout, NULL);
+      fprintf_unfiltered (mi->event_channel, "library-unloaded");
 
-  gdb_flush (mi->event_channel);
+      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);
+      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);
+    }
 }
 
 /* Emit notification about the command parameter change.  */
@@ -999,25 +1170,34 @@ 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 switch_thru_all_uis state;
 
   if (mi_suppress_notification.cmd_param_changed)
     return;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
 
-  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);
+      target_terminal_ours ();
 
-  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);
+
+      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);
+    }
 }
 
 /* Emit notification about the target memory change.  */
@@ -1026,45 +1206,54 @@ 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 switch_thru_all_uis state;
 
   if (mi_suppress_notification.memory)
     return;
 
-  target_terminal_ours ();
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+      struct ui_out *mi_uiout;
+      struct obj_section *sec;
 
-  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));
+      target_terminal_ours ();
 
-  /* 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);
+
+	  if (flags & SEC_CODE)
+	    ui_out_field_string (mi_uiout, "type", "code");
+	}
+
+      ui_out_redirect (mi_uiout, NULL);
+
+      gdb_flush (mi->event_channel);
+    }
 }
 
 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.  */
@@ -1161,4 +1350,35 @@ _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);
+
+  /* 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);
+
+  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 2daa03b..b97be4c 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -36,6 +36,8 @@ struct tl_interp_info;
 
 struct ui
 {
+  struct ui *next;
+
   /* The UI's line builder.  This is to used to accumulate input until
      we have a whole command line.  */
   struct buffer line_builder;
@@ -84,6 +86,24 @@ struct ui
 };
 
 extern struct ui *current_ui;
+extern struct ui *ui_list;
+
+struct switch_thru_all_uis
+{
+  struct ui *iter;
+  struct cleanup *old_chain;
+};
+
+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;
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index c7910bc..fc16f21 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -38,8 +38,13 @@ 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;
+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 +65,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 +84,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 +102,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 +120,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 +138,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 +156,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 +174,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 +187,17 @@ tui_on_sync_execution_done (void)
 static void
 tui_on_command_error (void)
 {
-  if (!interp_quiet_p (tui_interp))
-    display_gdb_prompt (NULL);
+  struct switch_thru_all_uis state;
+
+  SWITCH_THRU_ALL_UIS (state)
+    {
+      struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+      if (tui == NULL)
+	continue;
+
+      display_gdb_prompt (NULL);
+    }
 }
 
 /* These implement the TUI interpreter.  */
@@ -138,9 +208,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 +215,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;
 }
 
@@ -242,4 +299,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);
 }
-- 
1.9.3

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

* [PATCH 01/23] Test issuing a command split in multiple lines with continuation chars
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (5 preceding siblings ...)
  2016-02-03 16:44 ` [PATCH 02/23] Command line input handling TLC Pedro Alves
@ 2016-02-03 16:44 ` Pedro Alves
  2016-02-03 16:45 ` [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:44 UTC (permalink / raw)
  To: gdb-patches

I happened to break this locally and the testsuite didn't notice it.
Add some tests.
---
 .../gdb.base/command-continuation-char.exp         | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/command-continuation-char.exp

diff --git a/gdb/testsuite/gdb.base/command-continuation-char.exp b/gdb/testsuite/gdb.base/command-continuation-char.exp
new file mode 100644
index 0000000..68967b2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/command-continuation-char.exp
@@ -0,0 +1,34 @@
+# Copyright (C) 2014-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 issuing a command split in multiple lines with continuation
+# characters.
+
+gdb_exit
+gdb_start
+
+set test "print 1\\\\n + 2"
+gdb_test_multiple "print 1\\\n + 2" $test {
+    -re "^print 1\\\\\r\n \\+ 2\r\n\\\$$decimal = 3\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
+
+set test "print 1\\\\n2"
+gdb_test_multiple "print 1\\\n2" $test {
+    -re "^print 1\\\\\r\n2\r\n\\\$$decimal = 12\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
-- 
1.9.3

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

* Re: [PATCH 00/23] Towards great frontend GDB consoles
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (6 preceding siblings ...)
  2016-02-03 16:44 ` [PATCH 01/23] Test issuing a command split in multiple lines with continuation chars Pedro Alves
@ 2016-02-03 16:45 ` Pedro Alves
  2016-02-03 16:49 ` [PATCH 16/23] Introduce display_mi_prompt Pedro Alves
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:45 UTC (permalink / raw)
  To: gdb-patches, Marc Khouzam

Forgot to CC Marc...

On 02/03/2016 04:43 PM, Pedro Alves wrote:

> Marc asked if he could try the current version of this series, to try
> to get support for this on the Eclipse side ASAP, and maybe show it
> off at EclipseCon in a few weeks, so here it is, supposedly fully
> functional and all cleaned up ready for Eclipse testing, and general
> feedback.  :-)

... and mention that I pushed this to the users/palves/console branch
on sourceware.org.

Thanks,
Pedro Alves

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

* [PATCH 08/23] Make instream and serial_stdin be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (9 preceding siblings ...)
  2016-02-03 16:49 ` [PATCH 23/23] Add new command to create extra console/mi UI channels Pedro Alves
@ 2016-02-03 16:49 ` Pedro Alves
  2016-02-03 16:50 ` [PATCH 22/23] Only send sync execution command output to the UI that ran the command Pedro Alves
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:49 UTC (permalink / raw)
  To: gdb-patches

Note that in inflow.c, we always use the _main_ UI, not the current
UI.  What this means is that the inferior is always run on gdb's tty,
unless you use "set inferior-tty ..."
---
 gdb/cli/cli-script.c               | 11 +++++----
 gdb/event-top.c                    | 38 ++++++++++++++++++++-----------
 gdb/inflow.c                       | 40 +++++++++++++++++++++------------
 gdb/inflow.h                       |  4 ----
 gdb/main.c                         |  7 ++++--
 gdb/mi/mi-interp.c                 |  4 +++-
 gdb/python/python.c                |  3 ++-
 gdb/terminal.h                     |  6 +++--
 gdb/testsuite/gdb.gdb/selftest.exp |  4 ++++
 gdb/top.c                          | 46 +++++++++++++++++++++-----------------
 gdb/top.h                          | 11 ++++++++-
 gdb/utils.c                        |  4 +++-
 12 files changed, 114 insertions(+), 64 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 3dc95ab..ddeaf80 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -358,6 +358,7 @@ top_level_prompt (void)
 
 static struct ui main_ui_;
 
+struct ui *main_ui = &main_ui_;
 struct ui *current_ui = &main_ui_;
 struct ui *ui_list = &main_ui_;
 
@@ -418,7 +419,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
     {
@@ -465,11 +466,12 @@ async_disable_stdin (void)
 void
 command_handler (char *command)
 {
+  struct ui *ui = current_ui;
   struct cleanup *stat_chain;
   char *c;
 
   clear_quit_flag ();
-  if (instream == stdin)
+  if (ui->instream == stdin)
     reinitialize_more_filter ();
 
   stat_chain = make_command_stats_cleanup (1);
@@ -479,7 +481,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 ();
@@ -544,6 +546,7 @@ char *
 handle_line_of_input (struct buffer *cmd_builder,
 		      char *rl, int repeat, char *annotation_suffix)
 {
+  struct ui *ui = current_ui;
   char *p1;
   char *cmd;
 
@@ -558,7 +561,7 @@ handle_line_of_input (struct buffer *cmd_builder,
      command, but leave ownership of memory to the buffer .  */
   cmd_builder->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);
@@ -575,8 +578,8 @@ handle_line_of_input (struct buffer *cmd_builder,
     }
 
   /* 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;
@@ -645,10 +648,12 @@ handle_line_of_input (struct buffer *cmd_builder,
 void
 command_line_handler (char *rl)
 {
+  struct ui *ui = current_ui;
   struct buffer *cmd_builder = get_line_builder ();
   char *cmd;
 
-  cmd = handle_line_of_input (cmd_builder, rl, instream == stdin, "prompt");
+  cmd = handle_line_of_input (cmd_builder, rl,
+			      ui->instream == stdin, "prompt");
   if (cmd == (char *) EOF)
     {
       /* stdin closed.  The connection with the terminal is gone.
@@ -656,7 +661,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)
     {
@@ -692,7 +697,7 @@ gdb_readline_callback_no_editing (gdb_client_data client_data)
   while (1)
     {
       /* A non-blocking read.  */
-      c = serial_readchar (stdin_serial, 0);
+      c = serial_readchar (ui->stdin_serial, 0);
 
       if (c == SERIAL_ERROR)
 	{
@@ -821,7 +826,14 @@ handle_sigint (int sig)
 static void
 async_sigterm_handler (gdb_client_data arg)
 {
-  quit_force (NULL, stdin == instream);
+  struct ui *ui;
+
+  /* Async signal handlers have no connection to whichever was the
+     current UI, and thus always run on the main one.  */
+  ui = main_ui;
+  current_ui = ui;
+
+  quit_force (NULL, stdin == ui->instream);
 }
 
 /* See defs.h.  */
@@ -1003,7 +1015,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
@@ -1026,11 +1038,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/inflow.c b/gdb/inflow.c
index 4ccd806..147b687 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -31,6 +31,7 @@
 
 #include "inflow.h"
 #include "gdbcmd.h"
+#include "top.h"
 
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
@@ -48,8 +49,6 @@ static void child_terminal_ours_1 (int);
 \f
 /* Record terminal status separately for debugger and inferior.  */
 
-struct serial *stdin_serial;
-
 /* Terminal related info we need to keep track of.  Each inferior
    holds an instance of this structure --- we save it whenever the
    corresponding inferior stops, and restore it to the foreground
@@ -165,13 +164,17 @@ show_interactive_mode (struct ui_file *file, int from_tty,
 void
 set_initial_gdb_ttystate (void)
 {
-  initial_gdb_ttystate = serial_get_tty_state (stdin_serial);
+  struct ui *ui = main_ui;
+
+  initial_gdb_ttystate = serial_get_tty_state (ui->stdin_serial);
 }
 
 /* Does GDB have a terminal (on stdin)?  */
 int
 gdb_has_a_terminal (void)
 {
+  struct ui *ui = main_ui;
+
   if (interactive_mode != AUTO_BOOLEAN_AUTO)
     return interactive_mode == AUTO_BOOLEAN_TRUE;
 
@@ -192,9 +195,10 @@ gdb_has_a_terminal (void)
 #endif
 
       gdb_has_a_terminal_flag = no;
-      if (stdin_serial != NULL)
+      if (ui->stdin_serial != NULL)
 	{
-	  our_terminal_info.ttystate = serial_get_tty_state (stdin_serial);
+	  our_terminal_info.ttystate
+	    = serial_get_tty_state (ui->stdin_serial);
 
 	  if (our_terminal_info.ttystate != NULL)
 	    {
@@ -225,6 +229,7 @@ gdb_has_a_terminal (void)
 void
 child_terminal_init_with_pgrp (int pgrp)
 {
+  struct ui *ui = main_ui;
   struct inferior *inf = current_inferior ();
   struct terminal_info *tinfo = get_inflow_inferior_data (inf);
 
@@ -238,7 +243,7 @@ child_terminal_init_with_pgrp (int pgrp)
   if (gdb_has_a_terminal ())
     {
       xfree (tinfo->ttystate);
-      tinfo->ttystate = serial_copy_tty_state (stdin_serial,
+      tinfo->ttystate = serial_copy_tty_state (ui->stdin_serial,
 					       initial_gdb_ttystate);
 
       /* Make sure that next time we call terminal_inferior (which will be
@@ -255,10 +260,12 @@ child_terminal_init_with_pgrp (int pgrp)
 void
 gdb_save_tty_state (void)
 {
+  struct ui *ui = main_ui;
+
   if (gdb_has_a_terminal ())
     {
       xfree (our_terminal_info.ttystate);
-      our_terminal_info.ttystate = serial_get_tty_state (stdin_serial);
+      our_terminal_info.ttystate = serial_get_tty_state (ui->stdin_serial);
     }
 }
 
@@ -286,6 +293,7 @@ child_terminal_init (struct target_ops *self)
 void
 child_terminal_inferior (struct target_ops *self)
 {
+  struct ui *ui = main_ui;
   struct inferior *inf;
   struct terminal_info *tinfo;
 
@@ -313,7 +321,7 @@ child_terminal_inferior (struct target_ops *self)
       /* Because we were careful to not change in or out of raw mode in
          terminal_ours, we will not change in our out of raw mode with
          this call, so we don't flush any input.  */
-      result = serial_set_tty_state (stdin_serial,
+      result = serial_set_tty_state (ui->stdin_serial,
 				     tinfo->ttystate);
       OOPSY ("setting tty state");
 
@@ -394,6 +402,7 @@ child_terminal_ours (struct target_ops *self)
 static void
 child_terminal_ours_1 (int output_only)
 {
+  struct ui *ui = main_ui;
   struct inferior *inf;
   struct terminal_info *tinfo;
 
@@ -427,7 +436,7 @@ child_terminal_ours_1 (int output_only)
 #endif
 
       xfree (tinfo->ttystate);
-      tinfo->ttystate = serial_get_tty_state (stdin_serial);
+      tinfo->ttystate = serial_get_tty_state (ui->stdin_serial);
 
 #ifdef PROCESS_GROUP_TYPE
       if (!inf->attach_flag)
@@ -451,7 +460,8 @@ child_terminal_ours_1 (int output_only)
          though, since readline will deal with raw mode when/if it needs
          to.  */
 
-      serial_noflush_set_tty_state (stdin_serial, our_terminal_info.ttystate,
+      serial_noflush_set_tty_state (ui->stdin_serial,
+				    our_terminal_info.ttystate,
 				    tinfo->ttystate);
 
       if (job_control)
@@ -555,6 +565,7 @@ inflow_inferior_exit (struct inferior *inf)
 void
 copy_terminal_info (struct inferior *to, struct inferior *from)
 {
+  struct ui *ui = main_ui;
   struct terminal_info *tinfo_to, *tinfo_from;
 
   tinfo_to = get_inflow_inferior_data (to);
@@ -571,7 +582,7 @@ copy_terminal_info (struct inferior *to, struct inferior *from)
 
   if (tinfo_from->ttystate)
     tinfo_to->ttystate
-      = serial_copy_tty_state (stdin_serial, tinfo_from->ttystate);
+      = serial_copy_tty_state (ui->stdin_serial, tinfo_from->ttystate);
 }
 
 void
@@ -583,6 +594,7 @@ term_info (char *arg, int from_tty)
 void
 child_terminal_info (struct target_ops *self, const char *args, int from_tty)
 {
+  struct ui *ui = main_ui;
   struct inferior *inf;
   struct terminal_info *tinfo;
 
@@ -661,7 +673,7 @@ child_terminal_info (struct target_ops *self, const char *args, int from_tty)
   printf_filtered ("Process group = %d\n", (int) tinfo->process_group);
 #endif
 
-  serial_print_tty_state (stdin_serial, tinfo->ttystate, gdb_stdout);
+  serial_print_tty_state (ui->stdin_serial, tinfo->ttystate, gdb_stdout);
 }
 \f
 /* NEW_TTY_PREFORK is called before forking a new child process,
@@ -888,9 +900,9 @@ gdb_setpgid (void)
    that we can guarantee stdin_serial is opened if there is
    a terminal.  */
 void
-initialize_stdin_serial (void)
+initialize_stdin_serial (struct ui *ui)
 {
-  stdin_serial = serial_fdopen (0);
+  ui->stdin_serial = serial_fdopen (fileno (ui->instream));
 }
 
 void
diff --git a/gdb/inflow.h b/gdb/inflow.h
index 1c2278e..0d0242e 100644
--- a/gdb/inflow.h
+++ b/gdb/inflow.h
@@ -33,8 +33,4 @@
 extern PROCESS_GROUP_TYPE inferior_process_group (void);
 #endif
 
-/* The serial object that wraps stdin.  */
-
-extern struct serial *stdin_serial;
-
 #endif /* inflow.h */
diff --git a/gdb/main.c b/gdb/main.c
index 72d0369..89037cf 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -307,6 +307,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;
@@ -324,7 +326,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;
 }
 
@@ -433,6 +435,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;
@@ -503,7 +506,7 @@ captured_main (void *data)
 
   clear_quit_flag ();
   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 872c201..2d5d447 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -280,7 +280,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 a164e37..5d45093 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -328,6 +328,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;
 
@@ -351,7 +352,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/terminal.h b/gdb/terminal.h
index 4a00716..60a7e6d 100644
--- a/gdb/terminal.h
+++ b/gdb/terminal.h
@@ -77,6 +77,7 @@
 #endif
 
 struct inferior;
+struct ui;
 
 extern void new_tty_prefork (const char *);
 
@@ -96,8 +97,9 @@ extern pid_t create_tty_session (void);
    we lack job control.  */
 extern int gdb_setpgid (void);
 
-/* Set up a serial structure describing standard input.  In inflow.c.  */
-extern void initialize_stdin_serial (void);
+/* Set up a serial structure describing the UI's input.  In
+   inflow.c.  */
+extern void initialize_stdin_serial (struct ui *ui);
 
 extern int gdb_has_a_terminal (void);
 
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 3ecaaeb..dd6ec66 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -122,13 +122,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;
@@ -285,18 +278,21 @@ 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;
   command_loop ();
   do_cleanups (cleanups);
 }
@@ -548,14 +544,16 @@ execute_command_to_string (char *p, int from_tty)
 void
 command_loop (void)
 {
-  while (instream && !feof (instream))
+  struct ui *ui = current_ui;
+
+  while (ui->instream && !feof (ui->instream))
     {
       char *command;
 
       /* Get a command-line.  This calls the readline package.  */
-      command = command_line_input (instream == stdin ?
-				    get_prompt () : (char *) NULL,
-				    instream == stdin, "prompt");
+      command = command_line_input (ui->instream == stdin
+				    ? get_prompt () : (char *) NULL,
+				    ui->instream == stdin, "prompt");
       if (command == NULL)
 	return;
       command_handler (command);
@@ -572,13 +570,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;
 }
 
@@ -606,6 +606,7 @@ prevent_dont_repeat (void)
 static char *
 gdb_readline_no_editing (const char *prompt)
 {
+  struct ui *ui = current_ui;
   struct buffer line_builder;
 
   buffer_init (&line_builder);
@@ -625,7 +626,7 @@ gdb_readline_no_editing (const char *prompt)
 
       /* 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)
 	{
@@ -1030,6 +1031,7 @@ char *
 command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 {
   static struct buffer builder;
+  struct ui *ui = current_ui;
   const char *prompt = prompt_arg;
   char *cmd;
 
@@ -1040,7 +1042,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;
 
@@ -1081,7 +1083,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);
@@ -1492,16 +1494,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;
@@ -1937,7 +1941,7 @@ gdb_init (char *argv0)
   init_cli_cmds();
   init_main ();			/* But that omits this file!  Do it now.  */
 
-  initialize_stdin_serial ();
+  initialize_stdin_serial (current_ui);
 
   /* Take a snapshot of our tty state before readline/ncurses have had a chance
      to alter it.  */
diff --git a/gdb/top.h b/gdb/top.h
index b97be4c..6937eb3 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -67,6 +67,15 @@ 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 serial object that wraps stdin.  */
+  struct serial *stdin_serial;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
@@ -85,6 +94,7 @@ struct ui
   struct ui_file *m_gdb_stdlog;
 };
 
+extern struct ui *main_ui;
 extern struct ui *current_ui;
 extern struct ui *ui_list;
 
@@ -107,7 +117,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 e34c12e..bd3656c 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1021,10 +1021,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__
-- 
1.9.3

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

* [PATCH 16/23] Introduce display_mi_prompt
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (7 preceding siblings ...)
  2016-02-03 16:45 ` [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
@ 2016-02-03 16:49 ` Pedro Alves
  2016-02-03 16:49 ` [PATCH 23/23] Add new command to create extra console/mi UI channels Pedro Alves
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:49 UTC (permalink / raw)
  To: gdb-patches

Just a refactor.
---
 gdb/mi/mi-interp.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index d6b1aa4..e3ee939 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -88,6 +88,13 @@ static void mi_on_sync_execution_done (void);
 
 static int report_initial_inferior (struct inferior *inf, void *closure);
 
+static void
+display_mi_prompt (void)
+{
+  fputs_unfiltered ("(gdb) \n", raw_stdout);
+  gdb_flush (raw_stdout);
+}
+
 static struct mi_interp *
 as_mi_interp (struct interp *interp)
 {
@@ -296,10 +303,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.  */
@@ -315,10 +319,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
@@ -329,8 +330,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 ();
 }
-- 
1.9.3

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

* [PATCH 23/23] Add new command to create extra console/mi UI channels
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (8 preceding siblings ...)
  2016-02-03 16:49 ` [PATCH 16/23] Introduce display_mi_prompt Pedro Alves
@ 2016-02-03 16:49 ` Pedro Alves
  2016-02-03 16:49 ` [PATCH 08/23] Make instream and serial_stdin be per UI Pedro Alves
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:49 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
(yet).  It works as if "set editing off" was entered.

Starting more than one MI UI is probably very broken, because there
are still globals in the MI code that should be made per UI.  Should
be trivial to fix, though much lower priority than getting one MI
working.

(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 crashes, 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.  I should probably move this bit along with making main_ui
head allcoated earlier in the series.)
---
 gdb/event-top.c |  7 ++---
 gdb/interps.c   | 15 +++++++++-
 gdb/interps.h   |  5 ++++
 gdb/main.c      | 39 +++++++++-----------------
 gdb/top.c       | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/top.h       |  2 ++
 6 files changed, 122 insertions(+), 31 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 10c69f7..5da61cb 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -364,11 +364,10 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-static struct ui main_ui_;
 
-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;
 
 void
 restore_ui_cleanup (void *data)
diff --git a/gdb/interps.c b/gdb/interps.c
index 90d0de8..c9de292 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -291,6 +291,19 @@ interp_lookup (const char *name)
   return NULL;
 }
 
+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 *
@@ -523,7 +536,7 @@ interpreter_exec_cmd (char *args, int from_tty)
 }
 
 /* List the possible interpreters which could complete the given text.  */
-static VEC (char_ptr) *
+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 d33d632..0bad83d 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -86,6 +86,7 @@ extern struct interp *interp_new (const char *name,
 extern void interp_add (struct interp *interp);
 extern int interp_set (struct interp *interp, int top_level);
 extern struct interp *interp_lookup (const char *name);
+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);
@@ -119,6 +120,10 @@ 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);
 
+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 e107f60..a982752 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -441,7 +441,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;
@@ -513,26 +512,15 @@ captured_main (void *data)
   clear_quit_flag ();
   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 */
 
@@ -974,17 +962,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
@@ -1173,7 +1151,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 079db94..874d160 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -245,6 +245,83 @@ void (*deprecated_call_command_hook) (struct cmd_list_element * c,
 
 void (*deprecated_context_hook) (int id);
 
+struct ui *
+new_ui (FILE *instream, FILE *outstream, FILE *errstream)
+{
+  struct ui *ui;
+
+  ui = XCNEW (struct ui);
+
+  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;
+
+  ui->next = ui_list;
+  ui_list = ui;
+
+  return ui;
+}
+
+static void
+new_ui_command (char *args, int from_tty)
+{
+  struct ui *ui;
+  struct interp *interp;
+  FILE *stream;
+  int tty;
+  int res;
+  int argc;
+  char **argv;
+  const char *interpreter_name;
+  const char *tty_name;
+  struct cleanup *back_to;
+
+  argv = gdb_buildargv (args);
+  back_to = make_cleanup_freeargv (argv);
+
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  if (argc < 2)
+    error (_("usage: new-ui <interpreter> <tty>"));
+
+  interpreter_name = argv[0];
+  tty_name = argv[1];
+
+  /* Open the specified terminal.  */
+  tty = open (tty_name, O_RDWR | O_NOCTTY);
+  if (tty < 0)
+    perror_with_name  (_("opening terminal failed"));
+
+  stream = fdopen (tty, "w+");
+
+  ui = new_ui (stream, stream, stream);
+
+  initialize_stdin_serial (ui);
+  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
@@ -1802,6 +1879,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);
@@ -1925,6 +2004,12 @@ When set, GDB uses the specified path to search for data files."),
                            set_gdb_datadir, show_gdb_datadir,
                            &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
diff --git a/gdb/top.h b/gdb/top.h
index 6eb9cc6..72407b3 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -160,6 +160,8 @@ 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)		\
 
+extern struct ui *new_ui (FILE *instream, FILE *outstream, FILE *errstream);
+
 extern void restore_ui_cleanup (void *data);
 
 /* From top.c.  */
-- 
1.9.3

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

* [PATCH 22/23] Only send sync execution command output to the UI that ran the command
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (10 preceding siblings ...)
  2016-02-03 16:49 ` [PATCH 08/23] Make instream and serial_stdin be per UI Pedro Alves
@ 2016-02-03 16:50 ` Pedro Alves
  2016-02-03 16:50 ` [PATCH 15/23] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:50 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/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 2e20514..6f2597a 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -92,14 +92,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 e793bb4..49a7ab2 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);
 
@@ -68,14 +69,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));
     }
 }
-- 
1.9.3

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

* [PATCH 15/23] Make target_terminal_inferior/ours almost nops on non-main UIs
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (11 preceding siblings ...)
  2016-02-03 16:50 ` [PATCH 22/23] Only send sync execution command output to the UI that ran the command Pedro Alves
@ 2016-02-03 16:50 ` Pedro Alves
  2016-02-03 16:50 ` [PATCH 14/23] Always process target events in the main UI Pedro Alves
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:50 UTC (permalink / raw)
  To: gdb-patches

Since we always run the inferior in the main console (unless set
inferior--tty), 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/target.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/gdb/target.c b/gdb/target.c
index 86e7074..81bcca1 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -490,6 +490,9 @@ target_terminal_inferior (void)
 
   delete_file_handler (ui->input_fd);
 
+  if (ui != main_ui)
+    return;
+
   if (terminal_state == terminal_is_inferior)
     return;
 
@@ -508,6 +511,9 @@ target_terminal_ours (void)
 
   add_file_handler (ui->input_fd, stdin_event_handler, ui);
 
+  if (ui != main_ui)
+    return;
+
   if (terminal_state == terminal_is_ours)
     return;
 
@@ -520,6 +526,11 @@ target_terminal_ours (void)
 void
 target_terminal_ours_for_output (void)
 {
+  struct ui *ui = current_ui;
+
+  if (ui != main_ui)
+    return;
+
   if (terminal_state != terminal_is_inferior)
     return;
   (*current_target.to_terminal_ours_for_output) (&current_target);
-- 
1.9.3

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

* [PATCH 14/23] Always process target events in the main UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (12 preceding siblings ...)
  2016-02-03 16:50 ` [PATCH 15/23] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
@ 2016-02-03 16:50 ` Pedro Alves
  2016-02-03 16:50 ` [PATCH 19/23] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:50 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/event-top.c | 2 +-
 gdb/infrun.c    | 6 ++++++
 gdb/top.h       | 2 ++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index e2817c9..265787c 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -378,7 +378,7 @@ struct ui *main_ui = &main_ui_;
 struct ui *current_ui = &main_ui_;
 struct ui *ui_list = &main_ui_;
 
-static void
+void
 restore_ui_cleanup (void *data)
 {
   current_ui = (struct ui *) data;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 554b5c8..5200f1e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3867,6 +3867,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 223c7d0..3505319 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -131,6 +131,8 @@ 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))		\
 
+extern void restore_ui_cleanup (void *data);
+
 /* From top.c.  */
 extern char *saved_command_line;
 extern int in_user_command;
-- 
1.9.3

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

* [PATCH 12/23] Make current_ui_out be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (14 preceding siblings ...)
  2016-02-03 16:50 ` [PATCH 19/23] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
@ 2016-02-03 16:50 ` Pedro Alves
  2016-02-03 16:51 ` [PATCH 04/23] Make gdb_stdout&co " Pedro Alves
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:50 UTC (permalink / raw)
  To: gdb-patches

Similarly to gdb_stdout&co.
---
 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 dd6ec66..ddaf9c1 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -99,6 +99,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 1c43fb9..355bc0b 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -100,6 +100,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;
 };
 
 extern struct ui *main_ui;
diff --git a/gdb/ui-out.c b/gdb/ui-out.c
index 7f48d80..4d17396 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -153,11 +153,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
-- 
1.9.3

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

* [PATCH 19/23] Replace the sync_execution global with a new enum prompt_state tristate
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (13 preceding siblings ...)
  2016-02-03 16:50 ` [PATCH 14/23] Always process target events in the main UI Pedro Alves
@ 2016-02-03 16:50 ` Pedro Alves
  2016-02-03 16:50 ` [PATCH 12/23] Make current_ui_out be per UI Pedro Alves
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:50 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/annotate.c     |  15 ++------
 gdb/event-loop.c   |   2 +
 gdb/event-top.c    |  29 +++++++++-----
 gdb/infcall.c      |  27 +++++++++-----
 gdb/infcmd.c       |  28 ++++++++++----
 gdb/infrun.c       | 108 +++++++++++++++++++++++++++++++++++++++--------------
 gdb/infrun.h       |  10 ++---
 gdb/main.c         |  11 ++++--
 gdb/mi/mi-interp.c |  26 ++++++-------
 gdb/target.c       |   6 +--
 gdb/top.c          |   8 ++--
 gdb/top.h          |  25 +++++++++++++
 12 files changed, 198 insertions(+), 97 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 0e1cb2b..4840b7b 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -34,6 +34,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.  */
@@ -357,6 +358,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 d2623f6..10c69f7 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -277,7 +277,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
@@ -300,10 +304,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
@@ -445,14 +450,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;
     }
 }
 
@@ -462,7 +465,9 @@ async_enable_stdin (void)
 void
 async_disable_stdin (void)
 {
-  sync_execution = 1;
+  struct ui *ui = current_ui;
+
+  ui->prompt_state = PROMPT_BLOCKED;
 }
 \f
 
@@ -677,8 +682,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..29ac605 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;
 }
 
@@ -520,7 +527,8 @@ 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 ();
+      target_terminal_ours ();
+      f->waiting_ui->prompt_state = PROMPT_NEEDED;
     }
 
   return 1;
@@ -558,12 +566,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 +604,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 +1128,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 df13896..b26967c 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 ();
     }
 }
 
@@ -2687,8 +2701,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
@@ -2862,7 +2874,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 5200f1e..5f17d2f 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
@@ -3790,7 +3786,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,
@@ -3800,7 +3798,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 ();
 }
 
@@ -3833,6 +3831,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.  */
 
@@ -3860,7 +3888,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;
@@ -3980,14 +4007,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)))
@@ -4674,17 +4699,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
@@ -8240,10 +8280,14 @@ normal_stop (void)
 
   if (last.kind == TARGET_WAITKIND_NO_RESUMED)
     {
-      gdb_assert (sync_execution || !target_can_async_p ());
+      struct switch_thru_all_uis state;
 
-      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.  */
@@ -8255,8 +8299,16 @@ normal_stop (void)
   if (stopped_by_random_signal)
     disable_current_display ();
 
-  target_terminal_ours ();
-  async_enable_stdin ();
+  {
+    struct switch_thru_all_uis state;
+
+    target_terminal_ours ();
+
+    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 61d3b20..fae633e 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.  */
@@ -234,4 +229,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 1139487..e107f60 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -313,8 +313,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 ();
@@ -366,7 +367,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);
 
@@ -393,7 +394,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);
 
@@ -518,6 +519,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 cdbd48c..d8cfcf7 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -90,8 +90,11 @@ static int report_initial_inferior (struct inferior *inf, void *closure);
 static void
 display_mi_prompt (void)
 {
+  struct ui *ui = current_ui;
+
   fputs_unfiltered ("(gdb) \n", raw_stdout);
   gdb_flush (raw_stdout);
+  ui->prompt_state = PROMPTED;
 }
 
 static struct mi_interp *
@@ -165,13 +168,6 @@ mi_interpreter_resume (void *data)
 
   ui->call_readline = gdb_readline_callback_no_editing;
   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.  */
@@ -310,6 +306,10 @@ mi_on_sync_execution_done (void)
 static void
 mi_execute_command_input_handler (char *cmd)
 {
+  struct ui *ui = current_ui;
+
+  ui->prompt_state = PROMPT_NEEDED;
+
   mi_execute_command_wrapper (cmd);
 
   /* Print a prompt, indicating we're ready for further input, unless
@@ -317,7 +317,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 ();
 }
 
@@ -1051,12 +1051,10 @@ mi_on_resume_1 (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", raw_stdout);
     }
   gdb_flush (raw_stdout);
diff --git a/gdb/target.c b/gdb/target.c
index 81bcca1..746894f 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;
 
   delete_file_handler (ui->input_fd);
diff --git a/gdb/top.c b/gdb/top.c
index 79d5662..079db94 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -376,7 +376,7 @@ void
 wait_sync_command_done (void)
 {
   while (gdb_do_one_event () >= 0)
-    if (!sync_execution)
+    if (current_ui->prompt_state != PROMPT_BLOCKED)
       break;
 }
 
@@ -389,7 +389,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 ();
 }
 
@@ -426,7 +428,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 99a78c2..6eb9cc6 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
@@ -93,6 +111,9 @@ struct ui
   /* The serial object that wraps stdin.  */
   struct serial *stdin_serial;
 
+  /* 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.  */
@@ -135,6 +156,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)		\
+
 extern void restore_ui_cleanup (void *data);
 
 /* From top.c.  */
-- 
1.9.3

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

* [PATCH 21/23] Push thread->control.command_interp to the struct thread_fsm
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (16 preceding siblings ...)
  2016-02-03 16:51 ` [PATCH 04/23] Make gdb_stdout&co " Pedro Alves
@ 2016-02-03 16:51 ` Pedro Alves
  2016-02-03 16:51 ` [PATCH 17/23] Simplify starting the command event loop Pedro Alves
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:51 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., with 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)

(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" (no test
yet.)  Commands that rely on internal breakpoints, like "finish" would
still require more work to migrate breakpoints etc. to the child
thread.)
---
 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/thread-fsm.c     | 12 +++++----
 gdb/thread-fsm.h     | 23 +++++++++++-----
 gdb/thread.c         |  2 +-
 9 files changed, 90 insertions(+), 89 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1fad0d1..e3b0288 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -11605,8 +11605,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);
 
@@ -11624,14 +11626,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;
@@ -11644,10 +11646,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
@@ -11663,7 +11665,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;
 
@@ -11785,7 +11788,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 07c56c0..2e20514 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -74,10 +74,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 29ac605..38cec16 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;
 
@@ -1128,7 +1130,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,
@@ -1160,7 +1162,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 b26967c..27f3b11 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 5f17d2f..0e439fa 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
 		  {
@@ -2836,7 +2836,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.  */
@@ -3030,14 +3029,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
@@ -3811,7 +3802,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)
     {
@@ -3823,7 +3814,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)
@@ -3967,7 +3958,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/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;
     }
-- 
1.9.3

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

* [PATCH 13/23] Make command line editing (use of readline) be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (18 preceding siblings ...)
  2016-02-03 16:51 ` [PATCH 17/23] Simplify starting the command event loop Pedro Alves
@ 2016-02-03 16:51 ` Pedro Alves
  2016-02-03 16:51 ` [PATCH 10/23] Make outstream " Pedro Alves
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:51 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 (for now), 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.

(*) - I actually have a readline patch that makes is possible to have
multiple instances, but, I never posted it, and I suspect theat its
design would be rejected as is.  It's on my gihub if you'd like to see
it.
---
 gdb/cli/cli-interp.c |  16 +++++++-
 gdb/cli/cli-interp.h |  25 ++++++++++++
 gdb/event-top.c      | 105 ++++++++++++++++++++++++++++-----------------------
 gdb/event-top.h      |  10 ++---
 gdb/infrun.c         |   2 +-
 gdb/interps.c        |  10 +++++
 gdb/interps.h        |  11 ++++++
 gdb/mi/mi-interp.c   |   5 +--
 gdb/top.c            |  46 ++++++++++++++++------
 gdb/top.h            |   5 +++
 gdb/tui/tui-interp.c |   9 ++++-
 gdb/tui/tui-io.c     |   2 +-
 12 files changed, 172 insertions(+), 74 deletions(-)
 create mode 100644 gdb/cli/cli-interp.h

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index f994d47..afee7c5 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"
 
@@ -201,6 +203,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;
 
@@ -217,7 +220,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);
@@ -257,6 +262,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 */
 };
 
 static struct interp *
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 6883ad6..e2817c9 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -49,8 +49,6 @@
 #undef savestring
 
 static void rl_callback_read_char_wrapper (gdb_client_data client_data);
-static void command_line_handler (char *rl);
-static void change_line_handler (void);
 static char *top_level_prompt (void);
 
 /* Signal handlers.  */
@@ -89,7 +87,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.  */
@@ -151,36 +149,47 @@ cli_command_loop (void *data)
 /* 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
-   itself, via gdb_readline2.  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)
+   itself, via gdb_readline_callback_no_editing.  Also it is used in
+   the opposite case in which the user sets editing on again, by
+   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 = rl_callback_read_char_wrapper;
-      ui->input_handler = command_line_handler;
     }
   else
     {
-      /* Turn off editing by using gdb_readline2.  */
-      gdb_rl_callback_handler_remove ();
+      /* Turn off editing by using gdb_readline_callback_no_editing.  */
+      if (ui->command_editing)
+	gdb_rl_callback_handler_remove ();
       ui->call_readline = gdb_readline_callback_no_editing;
-
-      /* 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
@@ -201,6 +210,10 @@ static int callback_handler_installed;
 void
 gdb_rl_callback_handler_remove (void)
 {
+  struct ui *ui = current_ui;
+
+  gdb_assert (ui == main_ui);
+
   rl_callback_handler_remove ();
   callback_handler_installed = 0;
 }
@@ -214,6 +227,8 @@ gdb_rl_callback_handler_install (const char *prompt)
 {
   struct ui *ui = current_ui;
 
+  gdb_assert (ui == main_ui);
+
   /* Calling rl_callback_handler_install resets readline's input
      buffer.  Calling this when we were already processing input
      therefore loses input.  */
@@ -228,6 +243,10 @@ gdb_rl_callback_handler_install (const char *prompt)
 void
 gdb_rl_callback_handler_reinstall (void)
 {
+  struct ui *ui = current_ui;
+
+  gdb_assert (ui == main_ui);
+
   if (!callback_handler_installed)
     {
       /* Passing NULL as prompt argument tells readline to not display
@@ -289,7 +308,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;
 	}
@@ -302,7 +322,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);
@@ -986,19 +1006,12 @@ 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 (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;
 
@@ -1013,32 +1026,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 top level, 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 = 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_callback_no_editing;
     }
-  
-  /* 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
@@ -1050,6 +1059,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)
 {
@@ -1068,6 +1078,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 1b2cc59..31cb59e 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 7f0c3c9..554b5c8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3800,7 +3800,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 6626b4f..e9c96fd 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -395,6 +395,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 f80e563..b62f986 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -50,6 +50,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;
@@ -69,6 +71,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 form of
+     readline.  */
+  interp_supports_command_editing_ftype *supports_command_editing_proc;
 };
 
 extern struct interp *interp_new (const char *name,
@@ -104,6 +111,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 2d5d447..d6b1aa4 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -155,13 +155,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_callback_no_editing;
   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/top.c b/gdb/top.c
index ddaf9c1..eefc093 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -779,7 +779,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 ();
 }
 
@@ -799,7 +799,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;
@@ -837,7 +838,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 ();
 
@@ -849,7 +853,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) ();
@@ -1403,12 +1408,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;
 }
 
 
@@ -1722,13 +1733,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
@@ -1819,14 +1841,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 355bc0b..223c7d0 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -54,6 +54,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 simplified form of readline,
+     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 fc16f21..b71bd35 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"
@@ -221,6 +222,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
@@ -234,7 +236,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,
 };
 
 static struct interp *
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 18c648c..c00ec46 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;
 
-- 
1.9.3

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

* [PATCH 04/23] Make gdb_stdout&co be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (15 preceding siblings ...)
  2016-02-03 16:50 ` [PATCH 12/23] Make current_ui_out be per UI Pedro Alves
@ 2016-02-03 16:51 ` Pedro Alves
  2016-02-03 16:51 ` [PATCH 21/23] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:51 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.

I left gdb_stdtargin/stdtarg/stdtargerr global, but maybe that was a
mistake -- 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.  Likely
wouldn't work on all hosts though...
---
 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 93ed98f..44d1a90 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 21fbb0c..26aee8a 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -85,6 +85,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 66dbd2c..8beaa4a 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 4571aaf..ceee79d 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -152,18 +152,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
-- 
1.9.3

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

* [PATCH 10/23] Make outstream be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (19 preceding siblings ...)
  2016-02-03 16:51 ` [PATCH 13/23] Make command line editing (use of readline) be per UI Pedro Alves
@ 2016-02-03 16:51 ` Pedro Alves
  2016-02-03 16:52 ` [PATCH 09/23] Make input_fd " Pedro Alves
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:51 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/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 c94b365..6883ad6 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -1007,8 +1007,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 8ba86fc..3e5d870 100644
--- a/gdb/exceptions.c
+++ b/gdb/exceptions.c
@@ -26,6 +26,7 @@
 #include "ui-out.h"
 #include "serial.h"
 #include "gdbthread.h"
+#include "top.h"
 
 void
 prepare_to_throw_exception (void)
@@ -37,6 +38,7 @@ prepare_to_throw_exception (void)
 static void
 print_flush (void)
 {
+  struct ui *ui = current_ui;
   struct serial *gdb_stdout_serial;
 
   if (deprecated_error_begin_hook)
@@ -59,7 +61,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 eee9a8b..d070b4d 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -506,7 +506,11 @@ captured_main (void *data)
 
   clear_quit_flag ();
   saved_command_line = (char *) xstrdup ("");
+
   ui->instream = stdin;
+  ui->outstream = stdout;
+  ui->errstream = stderr;
+
   ui->input_fd = fileno (stdin);
 
 #ifdef __MINGW32__
@@ -516,7 +520,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 ef50489..1c43fb9 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -72,6 +72,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 c86994d..d72e161 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.  */
-- 
1.9.3

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

* [PATCH 17/23] Simplify starting the command event loop
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (17 preceding siblings ...)
  2016-02-03 16:51 ` [PATCH 21/23] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
@ 2016-02-03 16:51 ` Pedro Alves
  2016-02-03 16:51 ` [PATCH 13/23] Make command line editing (use of readline) be per UI Pedro Alves
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:51 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/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   |  7 ++-----
 gdb/tui/tui-interp.c |  2 +-
 8 files changed, 34 insertions(+), 35 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index afee7c5..f5fde57 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -192,6 +192,14 @@ cli_on_command_error (void)
     }
 }
 
+/* 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 265787c..d2623f6 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -133,19 +133,6 @@ rl_callback_read_char_wrapper (gdb_client_data client_data)
     (*after_char_processing_hook) ();
 }
 
-/* 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 e9c96fd..90d0de8 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -107,9 +107,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;
 }
 
@@ -383,16 +380,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 b62f986..d33d632 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -43,7 +43,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,
@@ -70,7 +70,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 form of
@@ -91,8 +93,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,
@@ -115,6 +115,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 d070b4d..1139487 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -313,7 +313,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 e3ee939..cdbd48c 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
@@ -323,7 +322,7 @@ mi_execute_command_input_handler (char *cmd)
 }
 
 static void
-mi_command_loop (void *data)
+mi_interpreter_pre_command_loop (struct interp *self)
 {
   /* Turn off 8 bit strings in quoted output.  Any character with the
      high bit set is printed using C's octal format.  */
@@ -331,8 +330,6 @@ mi_command_loop (void *data)
 
   /* Tell the world that we're alive.  */
   display_mi_prompt ();
-
-  start_event_loop ();
 }
 
 static void
@@ -1330,7 +1327,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 */
 };
 
 static struct interp *
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index b71bd35..e793bb4 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,
 };
 
-- 
1.9.3

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

* [PATCH 09/23] Make input_fd be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (20 preceding siblings ...)
  2016-02-03 16:51 ` [PATCH 10/23] Make outstream " Pedro Alves
@ 2016-02-03 16:52 ` Pedro Alves
  2016-02-03 16:52 ` [PATCH 05/23] Make the interpreters " Pedro Alves
  2016-02-03 16:53 ` [PATCH 20/23] New function should_print_stop_to_console Pedro Alves
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:52 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/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    | 10 ++++++++++
 gdb/top.h       |  4 ++++
 7 files changed, 29 insertions(+), 24 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index ddeaf80..c94b365 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -95,10 +95,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.  */
@@ -412,12 +408,16 @@ get_line_builder (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);
     }
@@ -1040,18 +1040,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
@@ -1060,6 +1053,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
@@ -1074,5 +1069,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 4f89626..1b2cc59 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_callback_no_editing (void *client_data);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 6ded38d..614231a 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4292,7 +4292,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 ();
 }
@@ -4318,7 +4317,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 89037cf..eee9a8b 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -507,6 +507,7 @@ captured_main (void *data)
   clear_quit_flag ();
   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 8831b50..52f44e0 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5948,7 +5948,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;
   async_initialize_sigint_signal_handler ();
   /* NOTE: At this point we could also register our selves as the
@@ -5967,7 +5966,6 @@ remote_terminal_ours (struct target_ops *self)
   if (remote_async_terminal_ours_p)
     return;
   async_cleanup_sigint_signal_handler (NULL);
-  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 ac66a3a..86e7074 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,8 @@ target_terminal_inferior (void)
   if (target_can_async_p () && !sync_execution)
     return;
 
+  delete_file_handler (ui->input_fd);
+
   if (terminal_state == terminal_is_inferior)
     return;
 
@@ -498,6 +504,10 @@ target_terminal_inferior (void)
 void
 target_terminal_ours (void)
 {
+  struct ui *ui = current_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 6937eb3..ef50489 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -73,6 +73,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 serial object that wraps stdin.  */
   struct serial *stdin_serial;
 
-- 
1.9.3

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

* [PATCH 05/23] Make the interpreters be per UI
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (21 preceding siblings ...)
  2016-02-03 16:52 ` [PATCH 09/23] Make input_fd " Pedro Alves
@ 2016-02-03 16:52 ` Pedro Alves
  2016-02-03 16:53 ` [PATCH 20/23] New function should_print_stop_to_console Pedro Alves
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:52 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/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         | 149 +++++++++++++++++++++++++++++++-------------------
 gdb/interps.h         |   9 ---
 gdb/main.c            |   2 +-
 gdb/python/python.c   |  12 ++--
 gdb/top.c             |   6 +-
 gdb/top.h             |  15 +++++
 14 files changed, 150 insertions(+), 107 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index afd9065..1fad0d1 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4720,7 +4720,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 7352b57..86964eb 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"
@@ -166,8 +166,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);
 
@@ -199,8 +199,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);
 
@@ -329,8 +329,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 a7d61af..b4e8ce6 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"
 
@@ -515,8 +515,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 15210c9..7f0c3c9 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3790,7 +3790,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,
@@ -3977,7 +3977,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..945b830 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -39,11 +39,29 @@
 #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;
+};
+
+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 +89,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 +116,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 +141,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 +166,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 +223,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 +245,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 +299,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 +321,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 +367,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 +407,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 +429,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 +467,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 +506,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 44d1a90..72d0369 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -309,7 +309,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 7202105..a164e37 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -331,8 +331,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);
 
@@ -476,8 +476,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)
@@ -659,8 +659,8 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
       char *copy = xstrdup (arg);
       struct cleanup *cleanup = make_cleanup (xfree, copy);
 
-      make_cleanup_restore_integer (&interpreter_async);
-      interpreter_async = 0;
+      make_cleanup_restore_integer (&current_ui->async);
+      current_ui->async = 0;
 
       prevent_dont_repeat ();
       if (to_string)
diff --git a/gdb/top.c b/gdb/top.c
index 26aee8a..3ecaaeb 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -392,7 +392,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 ();
 }
 
@@ -510,8 +510,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 8beaa4a..2daa03b 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.  */
-- 
1.9.3

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

* [PATCH 20/23] New function should_print_stop_to_console
  2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
                   ` (22 preceding siblings ...)
  2016-02-03 16:52 ` [PATCH 05/23] Make the interpreters " Pedro Alves
@ 2016-02-03 16:53 ` Pedro Alves
  23 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2016-02-03 16:53 UTC (permalink / raw)
  To: gdb-patches

Move this check to the cli interpreter code, so that we can reuse it
in the future with both the cli and tui interpreters.
---
 gdb/cli/cli-interp.c | 34 ++++++++++++++++++++++++++++++++++
 gdb/cli/cli-interp.h |  5 +++++
 gdb/mi/mi-interp.c   | 37 +++++++------------------------------
 gdb/mi/mi-main.c     |  2 +-
 4 files changed, 47 insertions(+), 31 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index f5fde57..07c56c0 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
@@ -48,6 +50,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 d8cfcf7..d784111 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.  */
@@ -617,12 +618,14 @@ 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,
      not the current one.  */
-  struct ui_out *mi_uiout = interp_ui_out (top_level_interpreter ());
+  struct mi_interp *mi = as_mi_interp (top_level_interpreter ());
+  struct ui_out *mi_uiout = mi->mi_uiout;
 
   if (print_frame)
     {
       struct thread_info *tp;
       int core;
+      struct interp *console_interp;
 
       tp = inferior_thread ();
 
@@ -637,36 +640,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 ()))
-	{
-	  struct mi_interp *mi
-	    = (struct mi_interp *) top_level_interpreter_data ();
+      console_interp = interp_lookup (INTERP_CONSOLE);
+      if (should_print_stop_to_console (console_interp, tp))
+	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);
       if (non_stop)
 	{
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index e25eedf..2c39316 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -2037,7 +2037,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);
 
-- 
1.9.3

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

end of thread, other threads:[~2016-02-03 16:53 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-03 16:44 [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
2016-02-03 16:44 ` [PATCH 11/23] Delete def_uiout Pedro Alves
2016-02-03 16:44 ` [PATCH 06/23] Introduce interpreter factories Pedro Alves
2016-02-03 16:44 ` [PATCH 18/23] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
2016-02-03 16:44 ` [PATCH 03/23] Introduce "struct ui" Pedro Alves
2016-02-03 16:44 ` [PATCH 07/23] Make the intepreters output to all UIs Pedro Alves
2016-02-03 16:44 ` [PATCH 02/23] Command line input handling TLC Pedro Alves
2016-02-03 16:44 ` [PATCH 01/23] Test issuing a command split in multiple lines with continuation chars Pedro Alves
2016-02-03 16:45 ` [PATCH 00/23] Towards great frontend GDB consoles Pedro Alves
2016-02-03 16:49 ` [PATCH 16/23] Introduce display_mi_prompt Pedro Alves
2016-02-03 16:49 ` [PATCH 23/23] Add new command to create extra console/mi UI channels Pedro Alves
2016-02-03 16:49 ` [PATCH 08/23] Make instream and serial_stdin be per UI Pedro Alves
2016-02-03 16:50 ` [PATCH 22/23] Only send sync execution command output to the UI that ran the command Pedro Alves
2016-02-03 16:50 ` [PATCH 15/23] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
2016-02-03 16:50 ` [PATCH 14/23] Always process target events in the main UI Pedro Alves
2016-02-03 16:50 ` [PATCH 19/23] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
2016-02-03 16:50 ` [PATCH 12/23] Make current_ui_out be per UI Pedro Alves
2016-02-03 16:51 ` [PATCH 04/23] Make gdb_stdout&co " Pedro Alves
2016-02-03 16:51 ` [PATCH 21/23] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
2016-02-03 16:51 ` [PATCH 17/23] Simplify starting the command event loop Pedro Alves
2016-02-03 16:51 ` [PATCH 13/23] Make command line editing (use of readline) be per UI Pedro Alves
2016-02-03 16:51 ` [PATCH 10/23] Make outstream " Pedro Alves
2016-02-03 16:52 ` [PATCH 09/23] Make input_fd " Pedro Alves
2016-02-03 16:52 ` [PATCH 05/23] Make the interpreters " Pedro Alves
2016-02-03 16:53 ` [PATCH 20/23] New function should_print_stop_to_console 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).