public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 00/25] Towards great frontend GDB consoles
@ 2016-03-21 15:21 Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 12/25] Make command line editing (use of readline) be per UI Pedro Alves
                   ` (27 more replies)
  0 siblings, 28 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marc Khouzam

Here's an update of the series I first posted here:
  https://sourceware.org/ml/gdb-patches/2016-02/msg00067.html

New in v2:

- The "Command line input handling TLC" patch [1] has since been split
  into a series of its own [2], and pushed in.

  [1] https://sourceware.org/ml/gdb-patches/2016-02/msg00070.html
  [2] https://sourceware.org/ml/gdb-patches/2016-02/msg00557.html

- Currently, if GDB's (main) stdin closes, GDB exits.  That logic
  carried over to secondary UIs as well, by mistake, so v1, if a
  secondary UI's terminal was closed, GDB would just exit as well...
  In v2, that's now detected, and GDB just discards the UI.

- I noticed that if you typed something in a secondary UI, and then
  Ctrl-C'd the main UI, GDB would internal error.  The problem was
  that nothing was making use async signal handlers (in this case,
  async_request_quit) always run on the main UI.

- Added a convenience "info uis" command to list UIs.

- Some cleanups here and there

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

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

Series intro:

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

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

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

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

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

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

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

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

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

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

 $ cat gdb-client
 #!/bin/bash

 reset
 tty
 tail -f /dev/null

 $ gdb-client
 /dev/pts/15

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

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

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

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

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

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

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

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

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

Pedro Alves (25):
  Introduce "struct ui"
  Make gdb_stdout&co be per UI
  Make the interpreters be per UI
  Introduce interpreter factories
  Make the intepreters output to all UIs
  Always run async signal handlers in the main UI
  Make instream 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
  Make main_ui be heap allocated
  Handle UI terminal closed
  Add new command to create extra console/mi UI channels
  Add command to list UIs

 gdb/annotate.c                     |  15 +-
 gdb/breakpoint.c                   |  21 +-
 gdb/cli/cli-interp.c               | 248 +++++++---
 gdb/cli/cli-interp.h               |  32 ++
 gdb/cli/cli-script.c               |  27 +-
 gdb/compile/compile.c              |  14 +-
 gdb/event-loop.c                   |   5 +
 gdb/event-top.c                    | 322 +++++++------
 gdb/event-top.h                    |  13 +-
 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                       |  23 +-
 gdb/infrun.c                       | 137 ++++--
 gdb/infrun.h                       |  10 +-
 gdb/interps.c                      | 262 +++++++---
 gdb/interps.h                      |  49 +-
 gdb/linux-nat.c                    |   2 -
 gdb/main.c                         |  53 +--
 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/testsuite/gdb.gdb/selftest.exp |   4 +
 gdb/thread-fsm.c                   |  12 +-
 gdb/thread-fsm.h                   |  23 +-
 gdb/thread.c                       |   2 +-
 gdb/top.c                          | 344 ++++++++++++--
 gdb/top.h                          | 154 +++++-
 gdb/tui/tui-interp.c               | 168 +++++--
 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 +-
 43 files changed, 2146 insertions(+), 1190 deletions(-)
 create mode 100644 gdb/cli/cli-interp.h

-- 
2.5.0

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

* [PATCH v2 02/25] Make gdb_stdout&co be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 12/25] Make command line editing (use of readline) be per UI Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 22/25] Make main_ui be heap allocated Pedro Alves
@ 2016-03-21 15:21 ` Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 03/25] Make the interpreters " Pedro Alves
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:21 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 913284a..ec10a34 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 fc4e90a..d404427 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -49,6 +49,23 @@ struct ui
   /* The function to invoke when a complete line of input is ready for
      processing.  */
   void (*input_handler) (char *);
+
+  /* The fields below that start with "m_" are "private".  They're
+     meant to be accessed through wrapper macros that make them look
+     like globals.  */
+
+  /* The ui_file streams.  */
+  /* Normal results */
+  struct ui_file *m_gdb_stdout;
+  /* Input stream */
+  struct ui_file *m_gdb_stdin;
+  /* Serious error notifications */
+  struct ui_file *m_gdb_stderr;
+  /* Log/debug/trace messages that should bypass normal stdout/stderr
+     filtering.  For moment, always call this stream using
+     *_unfiltered.  In the very near future that restriction shall be
+     removed - either call shall be unfiltered.  (cagney 1999-06-13).  */
+  struct ui_file *m_gdb_stdlog;
 };
 
 extern struct ui *current_ui;
diff --git a/gdb/utils.h b/gdb/utils.h
index 0687c86..bf77d7d 100644
--- a/gdb/utils.h
+++ b/gdb/utils.h
@@ -156,18 +156,27 @@ extern void reinitialize_more_filter (void);
 
 extern int pagination_enabled;
 
-/* Global ui_file streams.  These are all defined in main.c.  */
+extern struct ui_file **current_ui_gdb_stdout_ptr (void);
+extern struct ui_file **current_ui_gdb_stdin_ptr (void);
+extern struct ui_file **current_ui_gdb_stderr_ptr (void);
+extern struct ui_file **current_ui_gdb_stdlog_ptr (void);
+
+/* The current top level's ui_file streams.  */
+
 /* Normal results */
-extern struct ui_file *gdb_stdout;
+#define gdb_stdout (*current_ui_gdb_stdout_ptr ())
 /* Input stream */
-extern struct ui_file *gdb_stdin;
+#define gdb_stdin (*current_ui_gdb_stdin_ptr ())
 /* Serious error notifications */
-extern struct ui_file *gdb_stderr;
+#define gdb_stderr (*current_ui_gdb_stderr_ptr ())
 /* Log/debug/trace messages that should bypass normal stdout/stderr
    filtering.  For moment, always call this stream using
    *_unfiltered.  In the very near future that restriction shall be
    removed - either call shall be unfiltered.  (cagney 1999-06-13).  */
-extern struct ui_file *gdb_stdlog;
+#define gdb_stdlog (*current_ui_gdb_stdlog_ptr ())
+
+/* Truly global ui_file streams.  These are all defined in main.c.  */
+
 /* Target output that should bypass normal stdout/stderr filtering.
    For moment, always call this stream using *_unfiltered.  In the
    very near future that restriction shall be removed - either call
-- 
2.5.0

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

* [PATCH v2 22/25] Make main_ui be heap allocated
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 12/25] Make command line editing (use of readline) be per UI Pedro Alves
@ 2016-03-21 15:21 ` Pedro Alves
  2016-03-22 10:14   ` Yao Qi
  2016-03-21 15:21 ` [PATCH v2 02/25] Make gdb_stdout&co be per UI Pedro Alves
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:21 UTC (permalink / raw)
  To: gdb-patches

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

The change to gdb_main to stop using catch_errors is necessary because
catch_errors references current_uiout, which expands to
current_ui->m_current_ui, which would crash because current_ui is not
initialized yet at that point.  It didn't trigger earlier in the
series because before this patch, main_ui/current_ui always start out
non-NULL.
---
 gdb/event-top.c |  7 +++----
 gdb/main.c      | 27 ++++++++++++---------------
 gdb/top.c       | 37 +++++++++++++++++++++++++++++++++++++
 gdb/top.h       |  5 +++++
 4 files changed, 57 insertions(+), 19 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 436edf7..69f6be7 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -362,11 +362,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/main.c b/gdb/main.c
index e107f60..95578e4 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 */
 
@@ -1173,7 +1161,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 2941dbd..12064bc 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -245,6 +245,43 @@ void (*deprecated_call_command_hook) (struct cmd_list_element * c,
 
 void (*deprecated_context_hook) (int id);
 
+static int highest_ui_num;
+
+struct ui *
+new_ui (FILE *instream, FILE *outstream, FILE *errstream)
+{
+  struct ui *ui;
+
+  ui = XCNEW (struct ui);
+
+  ui->num = ++highest_ui_num;
+  ui->instream = instream;
+  ui->outstream = outstream;
+  ui->errstream = errstream;
+
+  ui->input_fd = fileno (ui->instream);
+
+  ui->m_gdb_stdin = stdio_fileopen (ui->instream);
+  ui->m_gdb_stdout = stdio_fileopen (ui->outstream);
+  ui->m_gdb_stderr = stderr_fileopen (ui->errstream);
+  ui->m_gdb_stdlog = ui->m_gdb_stderr;
+
+  ui->prompt_state = PROMPT_NEEDED;
+
+  if (ui_list == NULL)
+    ui_list = ui;
+  else
+    {
+      struct ui *last;
+
+      for (last = ui_list; last->next != NULL; last = last->next)
+	;
+      last->next = ui;
+    }
+
+  return ui;
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
diff --git a/gdb/top.h b/gdb/top.h
index 29deb3f..df76204 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -56,6 +56,9 @@ struct ui
 {
   struct ui *next;
 
+  /* Convenient handle (UI number).  Unique across all UIs.  */
+  int num;
+
   /* The UI's command line buffer.  This is to used to accumulate
      input until we have a whole command line.  */
   struct buffer line_buffer;
@@ -157,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.  */
-- 
2.5.0

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

* [PATCH v2 12/25] Make command line editing (use of readline) be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
@ 2016-03-21 15:21 ` Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 22/25] Make main_ui be heap allocated Pedro Alves
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:21 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      | 99 +++++++++++++++++++++++++++++-----------------------
 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, 169 insertions(+), 71 deletions(-)
 create mode 100644 gdb/cli/cli-interp.h

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index a14bca7..6e86e4d 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"
 
@@ -196,6 +198,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;
 
@@ -212,7 +215,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);
@@ -252,6 +257,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)
 {
@@ -296,7 +307,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 ea1e32e..964edff 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -47,8 +47,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.  */
@@ -87,7 +85,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,34 +149,45 @@ cli_command_loop (void *data)
    therefore bypassing readline, and letting gdb handle the input
    itself, via gdb_readline_no_editing_callback.  Also it is used in
    the opposite case in which the user sets editing on again, by
-   restoring readline handling of the input.  */
-static void
-change_line_handler (void)
+   restoring readline handling of the input.
+
+   NOTE: this operates on input_fd, not instream.  If we are reading
+   commands from a file, instream will point to the file.  However, we
+   always read commands from a file with editing off.  This means that
+   the 'set editing on/off' will have effect only on the interactive
+   session.  */
+
+void
+change_line_handler (int editing)
 {
   struct ui *ui = current_ui;
 
-  /* NOTE: this operates on input_fd, not instream.  If we are reading
-     commands from a file, instream will point to the file.  However in
-     async mode, we always read commands from a file with editing
-     off.  This means that the 'set editing on/off' will have effect
-     only on the interactive session.  */
+  /* We can only have one instance of readline, so we only allow
+     editing on the main UI.  */
+  if (ui != main_ui)
+    return;
+
+  /* Don't try enabling editing if the interpreter doesn't support it
+     (e.g., MI).  */
+  if (!interp_supports_command_editing (top_level_interpreter ())
+      || !interp_supports_command_editing (command_interp ()))
+    return;
 
-  if (async_command_editing_p)
+  if (editing)
     {
+      gdb_assert (ui == main_ui);
+
       /* Turn on editing by using readline.  */
       ui->call_readline = rl_callback_read_char_wrapper;
-      ui->input_handler = command_line_handler;
     }
   else
     {
       /* Turn off editing by using gdb_readline_no_editing_callback.  */
-      gdb_rl_callback_handler_remove ();
+      if (ui->command_editing)
+	gdb_rl_callback_handler_remove ();
       ui->call_readline = gdb_readline_no_editing_callback;
-
-      /* Set up the command handler as well, in case we are called as
-         first thing from .gdbinit.  */
-      ui->input_handler = command_line_handler;
     }
+  ui->command_editing = editing;
 }
 
 /* The functions below are wrappers for rl_callback_handler_remove and
@@ -199,6 +208,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;
 }
@@ -212,6 +225,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.  */
@@ -226,6 +241,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
@@ -287,7 +306,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;
 	}
@@ -300,7 +320,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);
@@ -990,19 +1010,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;
 
@@ -1017,32 +1030,28 @@ gdb_setup_readline (void)
   gdb_stdtarg = gdb_stderr; /* for moment */
   gdb_stdtargerr = gdb_stderr; /* for moment */
 
-  /* If the input stream is connected to a terminal, turn on
-     editing.  */
-  if (ISATTY (ui->instream))
+  /* If the input stream is connected to a terminal, turn on editing.
+     However, that is only allowed on the main UI, as we can only have
+     one instance of readline.  */
+  if (ISATTY (ui->instream) && editing && ui == main_ui)
     {
       /* Tell gdb that we will be using the readline library.  This
 	 could be overwritten by a command in .gdbinit like 'set
 	 editing on' or 'off'.  */
-      async_command_editing_p = 1;
-	  
+      ui->command_editing = 1;
+
       /* When a character is detected on instream by select or poll,
 	 readline will be invoked via this callback function.  */
       ui->call_readline = rl_callback_read_char_wrapper;
+
+      /* Tell readline to use the same input stream that gdb uses.  */
+      rl_instream = ui->instream;
     }
   else
     {
-      async_command_editing_p = 0;
+      ui->command_editing = 0;
       ui->call_readline = gdb_readline_no_editing_callback;
     }
-  
-  /* When readline has read an end-of-line character, it passes the
-     complete line to gdb for processing; command_line_handler is the
-     function that does this.  */
-  ui->input_handler = command_line_handler;
-
-  /* Tell readline to use the same input stream that gdb uses.  */
-  rl_instream = ui->instream;
 
   /* Now create the event source for this UI's input file descriptor.
      Another source is going to be the target program (inferior), but
@@ -1054,6 +1063,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)
 {
@@ -1072,6 +1082,7 @@ gdb_disable_readline (void)
   gdb_stdtargerr = NULL;
 #endif
 
-  gdb_rl_callback_handler_remove ();
+  if (ui->command_editing)
+    gdb_rl_callback_handler_remove ();
   delete_file_handler (ui->input_fd);
 }
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 4fe7737..dd0b4bc 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -28,12 +28,12 @@ struct cmd_list_element;
    FIXME: these should really go into top.h.  */
 
 extern void display_gdb_prompt (const char *new_prompt);
-void gdb_setup_readline (void);
-void gdb_disable_readline (void);
+extern void gdb_setup_readline (int);
+extern void gdb_disable_readline (void);
 extern void async_init_signals (void);
-extern void set_async_editing_command (char *args, int from_tty,
-				       struct cmd_list_element *c);
+extern void change_line_handler (int);
 
+extern void command_line_handler (char *rl);
 extern void command_handler (char *command);
 
 /* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT.  */
@@ -54,7 +54,7 @@ extern void async_enable_stdin (void);
 /* Exported variables from event-top.c.
    FIXME: these should really go into top.h.  */
 
-extern int async_command_editing_p;
+extern int set_editing_cmd_var;
 extern int exec_done_display_p;
 extern struct prompts the_prompts;
 extern void (*after_char_processing_hook) (void);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1a3df77..cfd072b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3801,7 +3801,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..7bcc0b9 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 readline
+     emulation.  */
+  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 f7003d0..e87041a 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_no_editing_callback;
   ui->input_handler = mi_execute_command_input_handler;
-  async_command_editing_p = 0;
   /* FIXME: This is a total hack for now.  PB's use of the MI
      implicitly relies on a bug in the async support which allows
      asynchronous commands to leak through the commmand loop.  The bug
diff --git a/gdb/top.c b/gdb/top.c
index 0d8a18a..56e21b1 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) ();
@@ -1411,12 +1416,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;
 }
 
 
@@ -1730,13 +1741,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
@@ -1827,14 +1849,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 a763f36..5967d73 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 simple readline emulation, with
+     no editing support.  */
+  int command_editing;
+
   /* Each UI has its own independent set of interpreters.  */
   struct ui_interp_info *interp_info;
 
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index a3fe955..2481a26 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"
@@ -216,6 +217,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
@@ -229,7 +231,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);
@@ -269,7 +273,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;
 
-- 
2.5.0

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

* [PATCH v2 03/25] Make the interpreters be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (2 preceding siblings ...)
  2016-03-21 15:21 ` [PATCH v2 02/25] Make gdb_stdout&co be per UI Pedro Alves
@ 2016-03-21 15:21 ` Pedro Alves
  2016-03-21 15:21 ` [PATCH v2 01/25] Introduce "struct ui" Pedro Alves
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:21 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 f99a7ab..b37baac 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4722,7 +4722,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 696105d..1a3df77 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3791,7 +3791,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,
@@ -3978,7 +3978,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 ec10a34..19b50c2 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 d404427..f18b79e 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -23,6 +23,8 @@
 #include "buffer.h"
 #include "event-loop.h"
 
+struct tl_interp_info;
+
 /* All about a user interface instance.  Each user interface has its
    own I/O files/streams, readline state, its own top level
    interpreter (for the main UI, this is the interpreter specified
@@ -50,6 +52,19 @@ struct ui
      processing.  */
   void (*input_handler) (char *);
 
+  /* Each UI has its own independent set of interpreters.  */
+  struct ui_interp_info *interp_info;
+
+  /* True if the UI is in async mode, false if in sync mode.  If in
+     sync mode, a synchronous execution command (e.g, "next") does not
+     return until the command is finished.  If in async mode, then
+     running a synchronous command returns right after resuming the
+     target.  Waiting for the command's completion is later done on
+     the top event loop.  For the main UI, this starts out disabled,
+     until all the explicit command line arguments (e.g., `gdb -ex
+     "start" -ex "next"') are processed.  */
+  int async;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
-- 
2.5.0

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

* [PATCH v2 01/25] Introduce "struct ui"
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (3 preceding siblings ...)
  2016-03-21 15:21 ` [PATCH v2 03/25] Make the interpreters " Pedro Alves
@ 2016-03-21 15:21 ` Pedro Alves
  2016-03-21 15:22 ` [PATCH v2 13/25] Always process target events in the main UI Pedro Alves
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:21 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    | 75 ++++++++++++++++++++++--------------------------------
 gdb/event-top.h    |  2 --
 gdb/mi/mi-interp.c |  5 ++--
 gdb/top.c          | 10 +++++---
 gdb/top.h          | 33 +++++++++++++++++++++++-
 5 files changed, 71 insertions(+), 54 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index eb4f0b9..a6d86fd 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -74,28 +74,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.  */
 
@@ -177,6 +159,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
@@ -186,18 +170,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_readline_no_editing_callback.  */
       gdb_rl_callback_handler_remove ();
-      call_readline = gdb_readline_no_editing_callback;
+      ui->call_readline = gdb_readline_no_editing_callback;
 
       /* Set up the command handler as well, in case we are called as
          first thing from .gdbinit.  */
-      input_handler = command_line_handler;
+      ui->input_handler = command_line_handler;
     }
 }
 
@@ -230,12 +214,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;
 }
 
@@ -368,22 +354,16 @@ top_level_prompt (void)
   return xstrdup (prompt);
 }
 
-/* Get a pointer to the command line buffer.  This is used to
+static struct ui current_ui_;
+struct ui *current_ui = &current_ui_;
+
+/* Get a pointer to the current UI's line buffer.  This is used to
    construct a whole line of input from partial input.  */
 
 static struct buffer *
 get_command_line_buffer (void)
 {
-  static struct buffer line_buffer;
-  static int line_buffer_initialized;
-
-  if (!line_buffer_initialized)
-    {
-      buffer_init (&line_buffer);
-      line_buffer_initialized = 1;
-    }
-
-  return &line_buffer;
+  return &current_ui->line_buffer;
 }
 
 /* When there is an event ready on the stdin file descriptor, instead
@@ -394,6 +374,8 @@ get_command_line_buffer (void)
 void
 stdin_event_handler (int error, gdb_client_data client_data)
 {
+  struct ui *ui = current_ui;
+
   if (error)
     {
       printf_unfiltered (_("error detected on stdin\n"));
@@ -406,7 +388,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);
     }
 }
@@ -664,6 +646,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
   char *result;
   struct buffer line_buffer;
   static int done_once = 0;
+  struct ui *ui = current_ui;
 
   buffer_init (&line_buffer);
 
@@ -703,7 +686,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
 	      break;
 	    }
 	  xfree (buffer_finish (&line_buffer));
-	  (*input_handler) (0);
+	  ui->input_handler (NULL);
 	  return;
 	}
 
@@ -720,7 +703,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
 
   buffer_grow_char (&line_buffer, '\0');
   result = buffer_finish (&line_buffer);
-  (*input_handler) (result);
+  ui->input_handler (result);
 }
 \f
 
@@ -980,6 +963,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
@@ -1002,19 +987,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_no_editing_callback;
+      ui->call_readline = gdb_readline_no_editing_callback;
     }
   
   /* When readline has read an end-of-line character, it passes the
      complete line to gdb for processing; command_line_handler is the
      function that does this.  */
-  input_handler = command_line_handler;
-      
+  ui->input_handler = command_line_handler;
+
   /* Tell readline to use the same input stream that gdb uses.  */
   rl_instream = instream;
 
diff --git a/gdb/event-top.h b/gdb/event-top.h
index bef2530..04956a5 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -57,8 +57,6 @@ extern void async_enable_stdin (void);
 extern int async_command_editing_p;
 extern int exec_done_display_p;
 extern struct prompts the_prompts;
-extern void (*call_readline) (void *);
-extern void (*input_handler) (char *);
 extern int input_fd;
 extern void (*after_char_processing_hook) (void);
 extern int call_stdin_event_handler_again_p;
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index d02012c..7ec51d3 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -174,6 +174,7 @@ static int
 mi_interpreter_resume (void *data)
 {
   struct mi_interp *mi = (struct mi_interp *) data;
+  struct ui *ui = current_ui;
 
   /* As per hack note in mi_interpreter_init, swap in the output
      channels... */
@@ -181,8 +182,8 @@ mi_interpreter_resume (void *data)
 
   /* These overwrite some of the initialization done in
      _intialize_event_loop.  */
-  call_readline = gdb_readline_no_editing_callback;
-  input_handler = mi_execute_command_input_handler;
+  ui->call_readline = gdb_readline_no_editing_callback;
+  ui->input_handler = mi_execute_command_input_handler;
   async_command_editing_p = 0;
   /* FIXME: This is a total hack for now.  PB's use of the MI
      implicitly relies on a bug in the async support which allows
diff --git a/gdb/top.c b/gdb/top.c
index 89fe832..913284a 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 a498f39..fc4e90a 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -20,7 +20,38 @@
 #ifndef TOP_H
 #define TOP_H
 
-struct buffer;
+#include "buffer.h"
+#include "event-loop.h"
+
+/* All about a user interface instance.  Each user interface has its
+   own I/O files/streams, readline state, its own top level
+   interpreter (for the main UI, this is the interpreter specified
+   with -i on the command line) and secondary interpreters (for
+   interpreter-exec ...), etc.  There's always one UI associated with
+   stdin/stdout/stderr, but the user can create secondary UIs, for
+   example, to create a separate MI channel on its own stdio
+   streams.  */
+
+struct ui
+{
+  /* The UI's command line buffer.  This is to used to accumulate
+     input until we have a whole command line.  */
+  struct buffer line_buffer;
+
+  /* The callback used by the event loop whenever an event is detected
+     on the UI's input file descriptor.  This function incrementally
+     builds a buffer where it accumulates the line read up to the
+     point of invocation.  In the special case in which the character
+     read is newline, the function invokes the INPUT_HANDLER callback
+     (see below).  */
+  void (*call_readline) (gdb_client_data);
+
+  /* The function to invoke when a complete line of input is ready for
+     processing.  */
+  void (*input_handler) (char *);
+};
+
+extern struct ui *current_ui;
 
 /* From top.c.  */
 extern char *saved_command_line;
-- 
2.5.0

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

* [PATCH v2 13/25] Always process target events in the main UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (4 preceding siblings ...)
  2016-03-21 15:21 ` [PATCH v2 01/25] Introduce "struct ui" Pedro Alves
@ 2016-03-21 15:22 ` Pedro Alves
  2016-03-22 10:26   ` Yao Qi
  2016-03-21 15:22 ` [PATCH v2 18/25] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:22 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 964edff..63f15c5 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -376,7 +376,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 cfd072b..b6524068 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3868,6 +3868,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 5967d73..de396a6 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -128,6 +128,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;
-- 
2.5.0

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

* [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (6 preceding siblings ...)
  2016-03-21 15:22 ` [PATCH v2 18/25] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
@ 2016-03-21 15:22 ` Pedro Alves
  2016-03-21 16:31   ` Eli Zaretskii
  2016-03-21 15:26 ` [PATCH v2 08/25] Make input_fd be per UI Pedro Alves
                   ` (19 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:22 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.
---
 gdb/interps.c | 15 +++++++++++-
 gdb/interps.h |  5 ++++
 gdb/main.c    | 12 +---------
 gdb/top.c     | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 12 deletions(-)

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 6d8930f..3f9f010 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 95578e4..a982752 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -962,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
diff --git a/gdb/top.c b/gdb/top.c
index 7d6d7cb..d74af46 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -313,6 +313,75 @@ delete_ui (struct ui *todel)
   free_ui (ui);
 }
 
+static FILE *
+open_stream (const char *name)
+{
+  int fd;
+
+  fd = open (name, O_RDWR | O_NOCTTY);
+  if (fd < 0)
+    perror_with_name  (_("opening terminal failed"));
+
+  return fdopen (fd, "w+");
+}
+
+static void
+new_ui_command (char *args, int from_tty)
+{
+  struct ui *ui;
+  struct interp *interp;
+  FILE *stream[3] = { NULL, NULL, NULL };
+  int i;
+  int res;
+  int argc;
+  char **argv;
+  const char *interpreter_name;
+  const char *tty_name;
+  struct cleanup *back_to;
+  struct cleanup *streams_chain;
+
+  argv = gdb_buildargv (args);
+  back_to = make_cleanup_freeargv (argv);
+
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  if (argc < 2)
+    error (_("usage: new-ui <interpreter> <tty>"));
+
+  interpreter_name = argv[0];
+  tty_name = argv[1];
+
+  streams_chain = make_cleanup (null_cleanup, NULL);
+
+  /* Open specified terminal, once for each of
+     stdin/stdout/stderr.  */
+  for (i = 0; i < 3; i++)
+    {
+      stream[i] = open_stream (tty_name);
+      make_cleanup_fclose (stream[i]);
+    }
+
+  ui = new_ui (stream[0], stream[1], stream[2]);
+
+  discard_cleanups (streams_chain);
+
+  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
@@ -1878,6 +1947,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);
@@ -2001,6 +2072,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
-- 
2.5.0

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

* [PATCH v2 18/25] Replace the sync_execution global with a new enum prompt_state tristate
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (5 preceding siblings ...)
  2016-03-21 15:22 ` [PATCH v2 13/25] Always process target events in the main UI Pedro Alves
@ 2016-03-21 15:22 ` Pedro Alves
  2016-03-21 15:22 ` [PATCH v2 24/25] Add new command to create extra console/mi UI channels Pedro Alves
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:22 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   |   1 +
 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, 197 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 c7062eb..6360eff 100644
--- a/gdb/event-loop.c
+++ b/gdb/event-loop.c
@@ -358,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 db4cb5e..436edf7 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -275,7 +275,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
@@ -298,10 +302,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
@@ -444,14 +449,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;
     }
 }
 
@@ -461,7 +464,9 @@ async_enable_stdin (void)
 void
 async_disable_stdin (void)
 {
-  sync_execution = 1;
+  struct ui *ui = current_ui;
+
+  ui->prompt_state = PROMPT_BLOCKED;
 }
 \f
 
@@ -678,8 +683,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 d687116..b812c1a 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -56,6 +56,7 @@
 #include "cli/cli-utils.h"
 #include "infcall.h"
 #include "thread-fsm.h"
+#include "top.h"
 
 /* Local functions: */
 
@@ -730,7 +731,7 @@ continue_1 (int all_threads)
 
       iterate_over_threads (proceed_thread_callback, NULL);
 
-      if (sync_execution)
+      if (current_ui->prompt_state == PROMPT_BLOCKED)
 	{
 	  /* If all threads in the target were already running,
 	     proceed_thread_callback ends up never calling proceed,
@@ -775,8 +776,6 @@ continue_command (char *args, int from_tty)
   args = strip_bg_char (args, &async_exec);
   args_chain = make_cleanup (xfree, args);
 
-  prepare_execution_command (&current_target, async_exec);
-
   if (args != NULL)
     {
       if (startswith (args, "-a"))
@@ -840,6 +839,17 @@ continue_command (char *args, int from_tty)
   /* Done with ARGS.  */
   do_cleanups (args_chain);
 
+  ERROR_NO_INFERIOR;
+  ensure_not_tfind_mode ();
+
+  if (!non_stop || !all_threads)
+    {
+      ensure_valid_thread ();
+      ensure_not_running ();
+    }
+
+  prepare_execution_command (&current_target, async_exec);
+
   if (from_tty)
     printf_filtered (_("Continuing.\n"));
 
@@ -1014,11 +1024,15 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
     proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
   else
     {
+      int proceeded;
+
       /* Stepped into an inline frame.  Pretend that we've
 	 stopped.  */
       thread_fsm_clean_up (thr->thread_fsm);
-      normal_stop ();
-      inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+      proceeded = normal_stop ();
+      if (!proceeded)
+	inferior_event_handler (INF_EXEC_COMPLETE, NULL);
+      all_uis_check_sync_execution_done ();
     }
 }
 
@@ -2691,8 +2705,6 @@ attach_post_wait (char *args, int from_tty, enum attach_post_wait_mode mode)
       /* The user requested a plain `attach', so be sure to leave
 	 the inferior stopped.  */
 
-      async_enable_stdin ();
-
       /* At least the current thread is already stopped.  */
 
       /* In all-stop, by definition, all threads have to be already
@@ -2866,7 +2878,7 @@ attach_command (char *args, int from_tty)
 	 STOP_QUIETLY_NO_SIGSTOP is for.  */
       inferior->control.stop_soon = STOP_QUIETLY_NO_SIGSTOP;
 
-      /* sync_execution mode.  Wait for stop.  */
+      /* Wait for stop.  */
       a = XNEW (struct attach_command_continuation_args);
       a->args = xstrdup (args);
       a->from_tty = from_tty;
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b6524068..39a8940 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
@@ -3791,7 +3787,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,
@@ -3801,7 +3799,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 ();
 }
 
@@ -3834,6 +3832,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.  */
 
@@ -3861,7 +3889,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;
@@ -3981,14 +4008,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)))
@@ -4675,17 +4700,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
@@ -8259,10 +8299,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.  */
@@ -8274,8 +8318,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 6d4936b..e13716a 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_no_editing_callback;
   ui->input_handler = mi_execute_command_input_handler;
-  /* FIXME: This is a total hack for now.  PB's use of the MI
-     implicitly relies on a bug in the async support which allows
-     asynchronous commands to leak through the commmand loop.  The bug
-     involves (but is not limited to) the fact that sync_execution was
-     erroneously initialized to 0.  Duplicate by initializing it thus
-     here...  */
-  sync_execution = 0;
 
   gdb_stdout = mi->out;
   /* Route error and log output through the MI.  */
@@ -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 dfbd911..2941dbd 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 e43875e..29deb3f 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
@@ -90,6 +108,9 @@ struct ui
      it with the event loop.  */
   int input_fd;
 
+  /* See enum prompt_state's description.  */
+  enum prompt_state prompt_state;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
@@ -132,6 +153,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.  */
-- 
2.5.0

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

* [PATCH v2 08/25] Make input_fd be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (7 preceding siblings ...)
  2016-03-21 15:22 ` [PATCH v2 24/25] Add new command to create extra console/mi UI channels Pedro Alves
@ 2016-03-21 15:26 ` Pedro Alves
  2016-03-22  9:46   ` Yao Qi
  2016-03-21 15:26 ` [PATCH v2 10/25] Delete def_uiout Pedro Alves
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:26 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 1ca2901..c7dba5a 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -93,10 +93,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.  */
@@ -411,12 +407,16 @@ get_command_line_buffer (void)
 void
 stdin_event_handler (int error, gdb_client_data client_data)
 {
-  struct ui *ui = current_ui;
+  struct ui *ui = (struct ui *) client_data;
+
+  /* Switch to the UI whose input descriptor woke up the event
+     loop.  */
+  current_ui = ui;
 
   if (error)
     {
       printf_unfiltered (_("error detected on stdin\n"));
-      delete_file_handler (input_fd);
+      delete_file_handler (ui->input_fd);
       /* If stdin died, we may as well kill gdb.  */
       quit_command ((char *) 0, stdin == ui->instream);
     }
@@ -1044,18 +1044,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
@@ -1064,6 +1057,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
@@ -1078,5 +1073,5 @@ gdb_disable_readline (void)
 #endif
 
   gdb_rl_callback_handler_remove ();
-  delete_file_handler (input_fd);
+  delete_file_handler (ui->input_fd);
 }
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 04956a5..4fe7737 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -57,7 +57,6 @@ extern void async_enable_stdin (void);
 extern int async_command_editing_p;
 extern int exec_done_display_p;
 extern struct prompts the_prompts;
-extern int input_fd;
 extern void (*after_char_processing_hook) (void);
 extern int call_stdin_event_handler_again_p;
 extern void gdb_readline_no_editing_callback (void *client_data);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0829bcb..69270fa 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4287,7 +4287,6 @@ linux_nat_terminal_inferior (struct target_ops *self)
   if (!async_terminal_is_ours)
     return;
 
-  delete_file_handler (input_fd);
   async_terminal_is_ours = 0;
   set_sigint_trap ();
 }
@@ -4313,7 +4312,6 @@ linux_nat_terminal_ours (struct target_ops *self)
     return;
 
   clear_sigint_trap ();
-  add_file_handler (input_fd, stdin_event_handler, 0);
   async_terminal_is_ours = 1;
 }
 
diff --git a/gdb/main.c b/gdb/main.c
index 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 af0a08a..2c0aaff 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5940,7 +5940,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
@@ -5959,7 +5958,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 d9322bd..beeb723 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 fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
-- 
2.5.0

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

* [PATCH v2 10/25] Delete def_uiout
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (8 preceding siblings ...)
  2016-03-21 15:26 ` [PATCH v2 08/25] Make input_fd be per UI Pedro Alves
@ 2016-03-21 15:26 ` Pedro Alves
  2016-03-21 15:27 ` [PATCH v2 15/25] Introduce display_mi_prompt Pedro Alves
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:26 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 e5a2bf1..4ea571b 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -147,84 +147,10 @@ pop_level (struct ui_out *uiout,
   return uiout->level + 1;
 }
 
-
-/* These are the default implementation functions.  */
-
-static void default_table_begin (struct ui_out *uiout, int nbrofcols,
-				 int nr_rows, const char *tblid);
-static void default_table_body (struct ui_out *uiout);
-static void default_table_end (struct ui_out *uiout);
-static void default_table_header (struct ui_out *uiout, int width,
-				  enum ui_align alig, const char *col_name,
-				  const char *colhdr);
-static void default_begin (struct ui_out *uiout,
-			   enum ui_out_type type,
-			   int level, const char *id);
-static void default_end (struct ui_out *uiout,
-			 enum ui_out_type type,
-			 int level);
-static void default_field_int (struct ui_out *uiout, int fldno, int width,
-			       enum ui_align alig,
-			       const char *fldname,
-			       int value);
-static void default_field_skip (struct ui_out *uiout, int fldno, int width,
-				enum ui_align alig,
-				const char *fldname);
-static void default_field_string (struct ui_out *uiout, int fldno, int width,
-				  enum ui_align align,
-				  const char *fldname,
-				  const char *string);
-static void default_field_fmt (struct ui_out *uiout, int fldno,
-			       int width, enum ui_align align,
-			       const char *fldname,
-			       const char *format,
-			       va_list args) ATTRIBUTE_PRINTF (6, 0);
-static void default_spaces (struct ui_out *uiout, int numspaces);
-static void default_text (struct ui_out *uiout, const char *string);
-static void default_message (struct ui_out *uiout, int verbosity,
-			     const char *format,
-			     va_list args) ATTRIBUTE_PRINTF (3, 0);
-static void default_wrap_hint (struct ui_out *uiout, char *identstring);
-static void default_flush (struct ui_out *uiout);
-static void default_data_destroy (struct ui_out *uiout);
-
-/* This is the default ui-out implementation functions vector.  */
-
-const struct ui_out_impl default_ui_out_impl =
-{
-  default_table_begin,
-  default_table_body,
-  default_table_end,
-  default_table_header,
-  default_begin,
-  default_end,
-  default_field_int,
-  default_field_skip,
-  default_field_string,
-  default_field_fmt,
-  default_spaces,
-  default_text,
-  default_message,
-  default_wrap_hint,
-  default_flush,
-  NULL, /* redirect */
-  default_data_destroy,
-  0, /* Does not need MI hacks.  */
-};
-
-/* The default ui_out */
-
-struct ui_out def_uiout =
-{
-  0,				/* flags */
-  &default_ui_out_impl,		/* impl */
-};
-
-/* Pointer to current ui_out */
 /* FIXME: This should not be a global, but something passed down from main.c
    or top.c.  */
 
-struct ui_out *current_uiout = &def_uiout;
+struct ui_out *current_uiout = NULL;
 
 /* These are the interfaces to implementation functions.  */
 
@@ -652,111 +578,6 @@ ui_out_is_mi_like_p (struct ui_out *uiout)
   return uiout->impl->is_mi_like_p;
 }
 
-/* Default gdb-out hook functions.  */
-
-static void
-default_table_begin (struct ui_out *uiout, int nbrofcols,
-		     int nr_rows,
-		     const char *tblid)
-{
-}
-
-static void
-default_table_body (struct ui_out *uiout)
-{
-}
-
-static void
-default_table_end (struct ui_out *uiout)
-{
-}
-
-static void
-default_table_header (struct ui_out *uiout, int width, enum ui_align alignment,
-		      const char *col_name,
-		      const char *colhdr)
-{
-}
-
-static void
-default_begin (struct ui_out *uiout,
-	       enum ui_out_type type,
-	       int level,
-	       const char *id)
-{
-}
-
-static void
-default_end (struct ui_out *uiout,
-	     enum ui_out_type type,
-	     int level)
-{
-}
-
-static void
-default_field_int (struct ui_out *uiout, int fldno, int width,
-		   enum ui_align align,
-		   const char *fldname, int value)
-{
-}
-
-static void
-default_field_skip (struct ui_out *uiout, int fldno, int width,
-		    enum ui_align align, const char *fldname)
-{
-}
-
-static void
-default_field_string (struct ui_out *uiout,
-		      int fldno,
-		      int width,
-		      enum ui_align align,
-		      const char *fldname,
-		      const char *string)
-{
-}
-
-static void
-default_field_fmt (struct ui_out *uiout, int fldno, int width,
-		   enum ui_align align,
-		   const char *fldname,
-		   const char *format,
-		   va_list args)
-{
-}
-
-static void
-default_spaces (struct ui_out *uiout, int numspaces)
-{
-}
-
-static void
-default_text (struct ui_out *uiout, const char *string)
-{
-}
-
-static void
-default_message (struct ui_out *uiout, int verbosity,
-		 const char *format,
-		 va_list args)
-{
-}
-
-static void
-default_wrap_hint (struct ui_out *uiout, char *identstring)
-{
-}
-
-static void
-default_flush (struct ui_out *uiout)
-{
-}
-
-static void
-default_data_destroy (struct ui_out *uiout)
-{
-}
-
 /* Interface to the implementation functions.  */
 
 void
-- 
2.5.0

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

* [PATCH v2 09/25] Make outstream be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (11 preceding siblings ...)
  2016-03-21 15:27 ` [PATCH v2 21/25] Only send sync execution command output to the UI that ran the command Pedro Alves
@ 2016-03-21 15:27 ` Pedro Alves
  2016-03-21 15:27 ` [PATCH v2 23/25] Handle UI terminal closed Pedro Alves
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:27 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 c7dba5a..ea1e32e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -1011,8 +1011,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 beeb723..2c4c9f1 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.  */
-- 
2.5.0

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

* [PATCH v2 21/25] Only send sync execution command output to the UI that ran the command
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (10 preceding siblings ...)
  2016-03-21 15:27 ` [PATCH v2 15/25] Introduce display_mi_prompt Pedro Alves
@ 2016-03-21 15:27 ` Pedro Alves
  2016-03-21 15:27 ` [PATCH v2 09/25] Make outstream be per UI Pedro Alves
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:27 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 15bba38..b2e0506 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 ef46837..5e59c5a 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));
     }
 }
-- 
2.5.0

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

* [PATCH v2 23/25] Handle UI terminal closed
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (12 preceding siblings ...)
  2016-03-21 15:27 ` [PATCH v2 09/25] Make outstream be per UI Pedro Alves
@ 2016-03-21 15:27 ` Pedro Alves
  2016-03-21 15:29 ` [PATCH v2 11/25] Make current_ui_out be per UI Pedro Alves
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:27 UTC (permalink / raw)
  To: gdb-patches

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

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

We want that for the main UI, but not secondary UIs.
---
 gdb/event-top.c | 25 ++++++++++++++++++-------
 gdb/top.c       | 31 +++++++++++++++++++++++++++++++
 gdb/top.h       |  1 +
 3 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 69f6be7..39b9633 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -420,19 +420,30 @@ stdin_event_handler (int error, gdb_client_data client_data)
 {
   struct ui *ui = (struct ui *) client_data;
 
-  /* Switch to the UI whose input descriptor woke up the event
-     loop.  */
-  current_ui = ui;
-
   if (error)
     {
-      printf_unfiltered (_("error detected on stdin\n"));
+      /* Switch to the main UI, so diagnostics always go there.  */
+      current_ui = main_ui;
+
       delete_file_handler (ui->input_fd);
-      /* If stdin died, we may as well kill gdb.  */
-      quit_command ((char *) 0, stdin == ui->instream);
+      if (main_ui == ui)
+	{
+	  /* If stdin died, we may as well kill gdb.  */
+	  printf_unfiltered (_("error detected on stdin\n"));
+	  quit_command ((char *) 0, stdin == ui->instream);
+	}
+      else
+	{
+	  /* Simply delete the UI.  */
+	  delete_ui (ui);
+	}
     }
   else
     {
+      /* Switch to the UI whose input descriptor woke up the event
+	 loop.  */
+      current_ui = ui;
+
       do
 	{
 	  call_stdin_event_handler_again_p = 0;
diff --git a/gdb/top.c b/gdb/top.c
index 12064bc..7d6d7cb 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -282,6 +282,37 @@ new_ui (FILE *instream, FILE *outstream, FILE *errstream)
   return ui;
 }
 
+static void
+free_ui (struct ui *ui)
+{
+  ui_file_delete (ui->m_gdb_stdin);
+  ui_file_delete (ui->m_gdb_stdout);
+  ui_file_delete (ui->m_gdb_stderr);
+
+  xfree (ui);
+}
+
+void
+delete_ui (struct ui *todel)
+{
+  struct ui *ui, *uiprev;
+
+  uiprev = NULL;
+
+  for (ui = ui_list; ui != NULL; uiprev = ui, ui = ui->next)
+    if (ui == todel)
+      break;
+
+  gdb_assert (ui != NULL);
+
+  if (uiprev != NULL)
+    uiprev->next = ui->next;
+  else
+    ui_list = ui->next;
+
+  free_ui (ui);
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
diff --git a/gdb/top.h b/gdb/top.h
index df76204..bac5a33 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -161,6 +161,7 @@ extern void switch_thru_all_uis_next (struct switch_thru_all_uis *state);
   for (UI = ui_list; UI; UI = UI->next)		\
 
 extern struct ui *new_ui (FILE *instream, FILE *outstream, FILE *errstream);
+extern void delete_ui (struct ui *todel);
 
 extern void restore_ui_cleanup (void *data);
 
-- 
2.5.0

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

* [PATCH v2 15/25] Introduce display_mi_prompt
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (9 preceding siblings ...)
  2016-03-21 15:26 ` [PATCH v2 10/25] Delete def_uiout Pedro Alves
@ 2016-03-21 15:27 ` Pedro Alves
  2016-03-21 15:27 ` [PATCH v2 21/25] Only send sync execution command output to the UI that ran the command Pedro Alves
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:27 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 e87041a..e1d186d 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 ();
 }
-- 
2.5.0

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

* [PATCH v2 05/25] Make the intepreters output to all UIs
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (16 preceding siblings ...)
  2016-03-21 15:29 ` [PATCH v2 17/25] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
@ 2016-03-21 15:29 ` Pedro Alves
  2016-03-22  9:33   ` Yao Qi
  2016-03-21 15:29 ` [PATCH v2 16/25] Simplify starting the command event loop Pedro Alves
                   ` (9 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:29 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 | 124 ++++++--
 gdb/event-top.c      |  40 ++-
 gdb/mi/mi-interp.c   | 806 ++++++++++++++++++++++++++++++++-------------------
 gdb/top.h            |  20 ++
 gdb/tui/tui-interp.c | 124 ++++++--
 5 files changed, 757 insertions(+), 357 deletions(-)

diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index bd50af7..a14bca7 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,12 @@ cli_on_sync_execution_done (void)
 static void
 cli_on_command_error (void)
 {
-  if (!interp_quiet_p (cli_interp))
-    display_gdb_prompt (NULL);
+  struct cli_interp *cli = as_cli_interp (top_level_interpreter ());
+
+  if (cli == NULL)
+    return;
+
+  display_gdb_prompt (NULL);
 }
 
 /* These implement the cli out interpreter: */
@@ -125,19 +190,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 +317,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 a6d86fd..05df8b8 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -354,8 +354,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 buffer.  This is used to
    construct a whole line of input from partial input.  */
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 06f1ae8..149f920 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 f18b79e..2cb0c90 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 command line buffer.  This is to used to accumulate
      input until we have a whole command line.  */
   struct buffer line_buffer;
@@ -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..a3fe955 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,12 @@ tui_on_sync_execution_done (void)
 static void
 tui_on_command_error (void)
 {
-  if (!interp_quiet_p (tui_interp))
-    display_gdb_prompt (NULL);
+  struct interp *tui = as_tui_interp (top_level_interpreter ());
+
+  if (tui == NULL)
+    return;
+
+  display_gdb_prompt (NULL);
 }
 
 /* These implement the TUI interpreter.  */
@@ -138,9 +203,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 +210,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 +294,14 @@ _initialize_tui_interp (void)
       xfree (interpreter_p);
       interpreter_p = xstrdup (INTERP_TUI);
     }
+
+  /* If changing this, remember to update cli-interp.c as well.  */
+  observer_attach_normal_stop (tui_on_normal_stop);
+  observer_attach_signal_received (tui_on_signal_received);
+  observer_attach_end_stepping_range (tui_on_end_stepping_range);
+  observer_attach_signal_exited (tui_on_signal_exited);
+  observer_attach_exited (tui_on_exited);
+  observer_attach_no_history (tui_on_no_history);
+  observer_attach_sync_execution_done (tui_on_sync_execution_done);
+  observer_attach_command_error (tui_on_command_error);
 }
-- 
2.5.0

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

* [PATCH v2 11/25] Make current_ui_out be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (13 preceding siblings ...)
  2016-03-21 15:27 ` [PATCH v2 23/25] Handle UI terminal closed Pedro Alves
@ 2016-03-21 15:29 ` Pedro Alves
  2016-03-21 15:29 ` [PATCH v2 04/25] Introduce interpreter factories Pedro Alves
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:29 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 4ecc99d..0d8a18a 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 2c4c9f1..a763f36 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -97,6 +97,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 4ea571b..3972a56 100644
--- a/gdb/ui-out.c
+++ b/gdb/ui-out.c
@@ -147,11 +147,6 @@ pop_level (struct ui_out *uiout,
   return uiout->level + 1;
 }
 
-/* FIXME: This should not be a global, but something passed down from main.c
-   or top.c.  */
-
-struct ui_out *current_uiout = NULL;
-
 /* These are the interfaces to implementation functions.  */
 
 static void uo_table_begin (struct ui_out *uiout, int nbrofcols,
diff --git a/gdb/ui-out.h b/gdb/ui-out.h
index 905d73c..9e1e74d 100644
--- a/gdb/ui-out.h
+++ b/gdb/ui-out.h
@@ -32,7 +32,8 @@ struct ui_file;
 
 /* FIXME: This should not be a global but something passed down from main.c
    or top.c.  */
-extern struct ui_out *current_uiout;
+extern struct ui_out **current_ui_current_uiout_ptr (void);
+#define current_uiout (*current_ui_current_uiout_ptr ())
 
 /* alignment enum */
 enum ui_align
-- 
2.5.0

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

* [PATCH v2 17/25] Make gdb_in_secondary_prompt_p() be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (15 preceding siblings ...)
  2016-03-21 15:29 ` [PATCH v2 04/25] Introduce interpreter factories Pedro Alves
@ 2016-03-21 15:29 ` Pedro Alves
  2016-03-21 15:29 ` [PATCH v2 05/25] Make the intepreters output to all UIs Pedro Alves
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:29 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 56e21b1..dfbd911 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 de396a6..e43875e 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
@@ -176,9 +180,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);
 
-- 
2.5.0

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

* [PATCH v2 04/25] Introduce interpreter factories
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (14 preceding siblings ...)
  2016-03-21 15:29 ` [PATCH v2 11/25] Make current_ui_out be per UI Pedro Alves
@ 2016-03-21 15:29 ` Pedro Alves
  2016-03-22  8:55   ` Yao Qi
  2016-03-21 15:29 ` [PATCH v2 17/25] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:29 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 7ec51d3..06f1ae8 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;
 
-- 
2.5.0

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

* [PATCH v2 16/25] Simplify starting the command event loop
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (17 preceding siblings ...)
  2016-03-21 15:29 ` [PATCH v2 05/25] Make the intepreters output to all UIs Pedro Alves
@ 2016-03-21 15:29 ` Pedro Alves
  2016-03-21 15:30 ` [PATCH v2 19/25] New function should_print_stop_to_console Pedro Alves
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:29 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 6e86e4d..11fad19 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -187,6 +187,14 @@ cli_on_command_error (void)
   display_gdb_prompt (NULL);
 }
 
+/* pre_command_loop implementation.  */
+
+void
+cli_interpreter_pre_command_loop (struct interp *self)
+{
+  display_gdb_prompt (0);
+}
+
 /* These implement the cli out interpreter: */
 
 static void *
@@ -307,7 +315,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 63f15c5..db4cb5e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -131,19 +131,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 7bcc0b9..6d8930f 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 readline
@@ -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 e1d186d..6d4936b 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 2481a26..ef46837 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -273,7 +273,7 @@ static const struct interp_procs tui_interp_procs = {
   tui_exec,
   tui_ui_out,
   NULL,
-  cli_command_loop,
+  cli_interpreter_pre_command_loop,
   cli_interpreter_supports_command_editing,
 };
 
-- 
2.5.0

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

* [PATCH v2 06/25] Always run async signal handlers in the main UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (20 preceding siblings ...)
  2016-03-21 15:30 ` [PATCH v2 07/25] Make instream and serial_stdin be per UI Pedro Alves
@ 2016-03-21 15:30 ` Pedro Alves
  2016-03-21 15:30 ` [PATCH v2 20/25] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:30 UTC (permalink / raw)
  To: gdb-patches

Async signal handlers have no connection to whichever was the current
UI, and thus always run on the main one.
---
 gdb/event-loop.c | 4 ++++
 gdb/event-top.c  | 1 +
 gdb/top.h        | 1 +
 3 files changed, 6 insertions(+)

diff --git a/gdb/event-loop.c b/gdb/event-loop.c
index 0e1cb2b..c7062eb 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.  */
@@ -946,6 +947,9 @@ invoke_async_signal_handlers (void)
 	break;
       any_ready = 1;
       async_handler_ptr->ready = 0;
+      /* Async signal handlers have no connection to whichever was the
+	 current UI, and thus always run on the main one.  */
+      current_ui = main_ui;
       (*async_handler_ptr->proc) (async_handler_ptr->client_data);
     }
 
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 05df8b8..b40ae93 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -356,6 +356,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_;
 
diff --git a/gdb/top.h b/gdb/top.h
index 2cb0c90..ef05942 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -85,6 +85,7 @@ struct ui
   struct ui_file *m_gdb_stdlog;
 };
 
+extern struct ui *main_ui;
 extern struct ui *current_ui;
 extern struct ui *ui_list;
 
-- 
2.5.0

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

* [PATCH v2 25/25] Add command to list UIs
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (22 preceding siblings ...)
  2016-03-21 15:30 ` [PATCH v2 20/25] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
@ 2016-03-21 15:30 ` Pedro Alves
  2016-03-22 10:36   ` Yao Qi
  2016-03-21 15:39 ` [PATCH v2 14/25] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
                   ` (3 subsequent siblings)
  27 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:30 UTC (permalink / raw)
  To: gdb-patches

Mainly a convenience at this point:

 $ gdb -q -ex "new-ui mi /dev/pts/7"
 (...)
 New UI allocated
 (gdb) info uis
   Num  Interpreter TTY
 * 1    tui
   2    mi          /dev/pts/7
 (gdb)
---
 gdb/interps.c | 20 +++++++++++++++-----
 gdb/interps.h |  1 +
 gdb/top.c     | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/top.h     |  3 +++
 4 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/gdb/interps.c b/gdb/interps.c
index c9de292..c211587 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -54,15 +54,19 @@ struct ui_interp_info
 };
 
 static struct ui_interp_info *
-get_current_interp_info (void)
+get_ui_interp_info (struct ui *ui)
 {
-  struct ui *ui = current_ui;
-
   if (ui->interp_info == NULL)
     ui->interp_info = XCNEW (struct ui_interp_info);
   return ui->interp_info;
 }
 
+static struct ui_interp_info *
+get_current_interp_info (void)
+{
+  return get_ui_interp_info (current_ui);
+}
+
 struct interp
 {
   /* This is the name in "-i=" and set interpreter.  */
@@ -577,13 +581,19 @@ interpreter_completer (struct cmd_list_element *ignore,
 }
 
 struct interp *
-top_level_interpreter (void)
+ui_top_level_interpreter (struct ui *ui)
 {
-  struct ui_interp_info *ui_interp = get_current_interp_info ();
+  struct ui_interp_info *ui_interp = get_ui_interp_info (ui);
 
   return ui_interp->top_level_interpreter_ptr;
 }
 
+struct interp *
+top_level_interpreter (void)
+{
+  return ui_top_level_interpreter (current_ui);
+}
+
 void *
 top_level_interpreter_data (void)
 {
diff --git a/gdb/interps.h b/gdb/interps.h
index 3f9f010..e752cdd 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -107,6 +107,7 @@ extern int current_interp_set_logging (int start_log, struct ui_file *out,
 /* Returns opaque data associated with the top-level interpreter.  */
 extern void *top_level_interpreter_data (void);
 extern struct interp *top_level_interpreter (void);
+extern struct interp *ui_top_level_interpreter (struct ui *ui);
 
 extern struct interp *command_interp (void);
 
diff --git a/gdb/top.c b/gdb/top.c
index d74af46..b05efc6 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -368,6 +368,7 @@ new_ui_command (char *args, int from_tty)
 
   initialize_stdin_serial (ui);
   ui->async = 1;
+  ui->tty_name = xstrdup (tty_name);
 
   make_cleanup (restore_ui_cleanup, current_ui);
   current_ui = ui;
@@ -382,6 +383,56 @@ new_ui_command (char *args, int from_tty)
   printf_unfiltered ("New UI allocated\n");
 }
 
+/* "info ui" command.  */
+
+static void
+info_uis_command (char *args, int from_tty)
+{
+  struct inferior *inf;
+  struct cleanup *old_chain;
+  int count = 0;
+  struct ui *ui = current_ui;
+  struct ui_out *uiout = current_uiout;
+
+  for (ui = ui_list; ui != NULL; ui = ui->next)
+    count++;
+
+  gdb_assert (count != 0);
+
+  old_chain = make_cleanup_ui_out_table_begin_end (uiout, 4, count, "UIs");
+  ui_out_table_header (uiout, 1, ui_left, "current", "");
+  ui_out_table_header (uiout, 4, ui_left, "number", "Num");
+  ui_out_table_header (uiout, 11, ui_left, "interp", "Interpreter");
+  ui_out_table_header (uiout, 17, ui_left, "tty", "TTY");
+
+  ui_out_table_body (uiout);
+  for (ui = ui_list; ui != NULL; ui = ui->next)
+    {
+      struct cleanup *chain2;
+
+      chain2 = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+
+      if (ui == current_ui)
+	ui_out_field_string (uiout, "current", "*");
+      else
+	ui_out_field_skip (uiout, "current");
+
+      ui_out_field_int (uiout, "number", ui->num);
+
+      ui_out_field_string (uiout, "interp",
+			   interp_name (ui_top_level_interpreter (ui)));
+      if (ui->tty_name != NULL)
+	ui_out_field_string (uiout, "tty", ui->tty_name);
+      else
+	ui_out_field_skip (uiout, "tty");
+
+      ui_out_text (uiout, "\n");
+      do_cleanups (chain2);
+    }
+
+  do_cleanups (old_chain);
+}
+
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
@@ -2078,6 +2129,9 @@ 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);
+
+  add_info ("uis", info_uis_command,
+	    _("IDs of specified UIs (all interfaces if no argument)."));
 }
 
 void
diff --git a/gdb/top.h b/gdb/top.h
index bac5a33..81ef466 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -59,6 +59,9 @@ struct ui
   /* Convenient handle (UI number).  Unique across all UIs.  */
   int num;
 
+  /* The TTY as passed to the "new-ui" command.  */
+  const char *tty_name;
+
   /* The UI's command line buffer.  This is to used to accumulate
      input until we have a whole command line.  */
   struct buffer line_buffer;
-- 
2.5.0

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

* [PATCH v2 07/25] Make instream and serial_stdin be per UI
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (19 preceding siblings ...)
  2016-03-21 15:30 ` [PATCH v2 19/25] New function should_print_stop_to_console Pedro Alves
@ 2016-03-21 15:30 ` Pedro Alves
  2016-03-21 15:30 ` [PATCH v2 06/25] Always run async signal handlers in the main UI Pedro Alves
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:30 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                    | 34 +++++++++++++++-------------
 gdb/inflow.c                       | 23 ++++++++++++++-----
 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                          |  7 +++++-
 gdb/utils.c                        |  4 +++-
 11 files changed, 95 insertions(+), 54 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 b40ae93..1ca2901 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -418,7 +418,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 +465,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 +480,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 ();
@@ -546,6 +547,7 @@ char *
 handle_line_of_input (struct buffer *cmd_line_buffer,
 		      char *rl, int repeat, char *annotation_suffix)
 {
+  struct ui *ui = current_ui;
   char *p1;
   char *cmd;
 
@@ -560,7 +562,7 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
      command, but leave ownership of memory to the buffer .  */
   cmd_line_buffer->used_size = 0;
 
-  if (annotation_level > 1 && instream == stdin)
+  if (annotation_level > 1 && ui->instream == stdin)
     {
       printf_unfiltered (("\n\032\032post-"));
       puts_unfiltered (annotation_suffix);
@@ -577,8 +579,8 @@ handle_line_of_input (struct buffer *cmd_line_buffer,
     }
 
   /* Do history expansion if that is wished.  */
-  if (history_expansion_p && instream == stdin
-      && ISATTY (instream))
+  if (history_expansion_p && ui->instream == stdin
+      && ISATTY (ui->instream))
     {
       char *history_value;
       int expanded;
@@ -648,9 +650,11 @@ void
 command_line_handler (char *rl)
 {
   struct buffer *line_buffer = get_command_line_buffer ();
+  struct ui *ui = current_ui;
   char *cmd;
 
-  cmd = handle_line_of_input (line_buffer, rl, instream == stdin, "prompt");
+  cmd = handle_line_of_input (line_buffer, rl, ui->instream == stdin,
+			      "prompt");
   if (cmd == (char *) EOF)
     {
       /* stdin closed.  The connection with the terminal is gone.
@@ -658,7 +662,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)
     {
@@ -693,9 +697,9 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
      stream after '\n'.  If we buffer the input and fgetc drains the
      stream, getting stuff beyond the newline as well, a select, done
      afterwards will not trigger.  */
-  if (!done_once && !ISATTY (instream))
+  if (!done_once && !ISATTY (ui->instream))
     {
-      setbuf (instream, NULL);
+      setbuf (ui->instream, NULL);
       done_once = 1;
     }
 
@@ -711,7 +715,7 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
     {
       /* Read from stdin if we are executing a user defined command.
          This is the right thing for prompt_for_continue, at least.  */
-      c = fgetc (instream ? instream : stdin);
+      c = fgetc (ui->instream ? ui->instream : stdin);
 
       if (c == EOF)
 	{
@@ -833,7 +837,7 @@ handle_sigint (int sig)
 static void
 async_sigterm_handler (gdb_client_data arg)
 {
-  quit_force (NULL, stdin == instream);
+  quit_force (NULL, stdin == current_ui->instream);
 }
 
 /* See defs.h.  */
@@ -1015,7 +1019,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
@@ -1038,11 +1042,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 4c80dbd..2b12090 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>
@@ -172,6 +173,8 @@ set_initial_gdb_ttystate (void)
 int
 gdb_has_a_terminal (void)
 {
+  struct ui *ui = main_ui;
+
   if (interactive_mode != AUTO_BOOLEAN_AUTO)
     return interactive_mode == AUTO_BOOLEAN_TRUE;
 
@@ -194,7 +197,8 @@ gdb_has_a_terminal (void)
       gdb_has_a_terminal_flag = no;
       if (stdin_serial != NULL)
 	{
-	  our_terminal_info.ttystate = serial_get_tty_state (stdin_serial);
+	  our_terminal_info.ttystate
+	    = serial_get_tty_state (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);
 
@@ -255,6 +260,8 @@ 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);
@@ -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,8 +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,
-				     tinfo->ttystate);
+      result = serial_set_tty_state (stdin_serial, tinfo->ttystate);
       OOPSY ("setting tty state");
 
       if (!job_control)
@@ -394,6 +401,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;
 
@@ -451,7 +459,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 (stdin_serial,
+				    our_terminal_info.ttystate,
 				    tinfo->ttystate);
 
       if (job_control)
@@ -555,6 +564,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);
@@ -583,6 +593,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;
 
@@ -888,9 +899,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);
+  stdin_serial = serial_fdopen (fileno (ui->instream));
 }
 
 void
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 149f920..f7003d0 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 19b50c2..4ecc99d 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;
 }
 
@@ -607,6 +607,7 @@ static char *
 gdb_readline_no_editing (const char *prompt)
 {
   struct buffer line_buffer;
+  struct ui *ui = current_ui;
 
   buffer_init (&line_buffer);
 
@@ -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)
 	{
@@ -1031,6 +1032,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 {
   static struct buffer cmd_line_buffer;
   static int cmd_line_buffer_initialized;
+  struct ui *ui = current_ui;
   const char *prompt = prompt_arg;
   char *cmd;
 
@@ -1038,7 +1040,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;
 
@@ -1088,7 +1090,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);
@@ -1500,16 +1502,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;
@@ -1945,7 +1949,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 ef05942..d9322bd 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -67,6 +67,12 @@ struct ui
      "start" -ex "next"') are processed.  */
   int async;
 
+  /* stdio stream that command input is being read from.  Set to stdin
+     normally.  Set by source_command to the file we are sourcing.
+     Set to NULL if we are executing a user-defined command or
+     interacting via a GUI.  */
+  FILE *instream;
+
   /* The fields below that start with "m_" are "private".  They're
      meant to be accessed through wrapper macros that make them look
      like globals.  */
@@ -108,7 +114,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 97e5133..d1a56ef 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__
-- 
2.5.0

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

* [PATCH v2 19/25] New function should_print_stop_to_console
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (18 preceding siblings ...)
  2016-03-21 15:29 ` [PATCH v2 16/25] Simplify starting the command event loop Pedro Alves
@ 2016-03-21 15:30 ` Pedro Alves
  2016-03-21 15:30 ` [PATCH v2 07/25] Make instream and serial_stdin be per UI Pedro Alves
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:30 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 11fad19..3b81015 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 e13716a..42d1221 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);
 
-- 
2.5.0

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

* [PATCH v2 20/25] Push thread->control.command_interp to the struct thread_fsm
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (21 preceding siblings ...)
  2016-03-21 15:30 ` [PATCH v2 06/25] Always run async signal handlers in the main UI Pedro Alves
@ 2016-03-21 15:30 ` Pedro Alves
  2016-03-21 15:30 ` [PATCH v2 25/25] Add command to list UIs Pedro Alves
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:30 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 b37baac..89a78b9 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -11603,8 +11603,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);
 
@@ -11622,14 +11624,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;
@@ -11642,10 +11644,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
@@ -11661,7 +11663,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;
 
@@ -11783,7 +11786,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 3b81015..15bba38 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 b812c1a..583002f 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 39a8940..a23bb38 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
 		  {
@@ -2837,7 +2837,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.  */
@@ -3031,14 +3030,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
@@ -3812,7 +3803,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)
     {
@@ -3824,7 +3815,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)
@@ -3968,7 +3959,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;
     }
-- 
2.5.0

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

* [PATCH v2 14/25] Make target_terminal_inferior/ours almost nops on non-main UIs
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (23 preceding siblings ...)
  2016-03-21 15:30 ` [PATCH v2 25/25] Add command to list UIs Pedro Alves
@ 2016-03-21 15:39 ` Pedro Alves
  2016-03-21 16:34 ` [PATCH v2 00/25] Towards great frontend GDB consoles Eli Zaretskii
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 15:39 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);
-- 
2.5.0

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-03-21 15:22 ` [PATCH v2 24/25] Add new command to create extra console/mi UI channels Pedro Alves
@ 2016-03-21 16:31   ` Eli Zaretskii
  2016-03-21 16:51     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Eli Zaretskii @ 2016-03-21 16:31 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> From: Pedro Alves <palves@redhat.com>
> Date: Mon, 21 Mar 2016 15:21:14 +0000
> 
> With all the previous plumbing in place, it's now easy to add a
> command that actually creates a new console/mi UI.

Shouldn't this (and other related) code be conditional of PTYs being
supported?  Otherwise, this is just useless baggage, right?

Thanks.

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (24 preceding siblings ...)
  2016-03-21 15:39 ` [PATCH v2 14/25] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
@ 2016-03-21 16:34 ` Eli Zaretskii
  2016-03-21 17:02   ` Pedro Alves
  2016-03-21 18:35 ` Marc Khouzam
  2016-03-22 10:41 ` Yao Qi
  27 siblings, 1 reply; 58+ messages in thread
From: Eli Zaretskii @ 2016-03-21 16:34 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, marc.khouzam

> From: Pedro Alves <palves@redhat.com>
> Cc: Marc Khouzam <marc.khouzam@ericsson.com>
> Date: Mon, 21 Mar 2016 15:20:50 +0000
> 
>   Add new command to create extra console/mi UI channels
>   Add command to list UIs

Are these commands intended to remain undocumented?

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-03-21 16:31   ` Eli Zaretskii
@ 2016-03-21 16:51     ` Pedro Alves
  2016-03-21 17:12       ` Eli Zaretskii
  0 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 16:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

Hi Eli,

On 03/21/2016 04:30 PM, Eli Zaretskii wrote:
>> From: Pedro Alves <palves@redhat.com>
>> Date: Mon, 21 Mar 2016 15:21:14 +0000
>>
>> With all the previous plumbing in place, it's now easy to add a
>> command that actually creates a new console/mi UI.
> 
> Shouldn't this (and other related) code be conditional of PTYs being
> supported?  Otherwise, this is just useless baggage, right?

Actually this should all work on Windows too, for example.

MI doesn't really need a PTY, so even though currently the command's
online help and git logs say usage is "new-ui INTERP TTY", that TTY part
could actually be the name of any bidirectional stream.

E.g., it could be a bidi unix domain socket, on Linux, or on Windows,
I think it should work to pass a console name, or a bidirectional
named pipe path, though I haven't tried it.

If necessary, it would also be easy to extend the command to support
separate streams for in/out/err, like, e.g.:

 (gdb) new-ui INTERP IN OUT ERR

And then it'd be possible to open a new MI channel through
unidirectional named pipes, regular files, etc. too.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 16:34 ` [PATCH v2 00/25] Towards great frontend GDB consoles Eli Zaretskii
@ 2016-03-21 17:02   ` Pedro Alves
  2016-03-21 17:17     ` Eli Zaretskii
  2016-03-21 17:43     ` Marc Khouzam
  0 siblings, 2 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 17:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, marc.khouzam

On 03/21/2016 04:34 PM, Eli Zaretskii wrote:
>> From: Pedro Alves <palves@redhat.com>
>> Cc: Marc Khouzam <marc.khouzam@ericsson.com>
>> Date: Mon, 21 Mar 2016 15:20:50 +0000
>>
>>    Add new command to create extra console/mi UI channels
>>    Add command to list UIs
> 
> Are these commands intended to remain undocumented?

No, they'll absolutely be documented.  I haven't managed to write
them documentation yet, as well as ChangeLogs, etc.  Sorry about that.

The current state of the series is that I think it works correctly and
that the exposed command is about what GDB should be exposing.  But experience
with integrating it with frontends may prove otherwise. :-)  So I'm
posting this to both try to get frontends to experiment with implementing
support for it, and collecting feedback from the GDB side as well.  At least
support in Eclipse is actively being worked on, though I'd think it
great if other frontends learned to use this as well.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-03-21 16:51     ` Pedro Alves
@ 2016-03-21 17:12       ` Eli Zaretskii
  2016-03-21 17:57         ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Eli Zaretskii @ 2016-03-21 17:12 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Mon, 21 Mar 2016 16:51:21 +0000
> 
> > Shouldn't this (and other related) code be conditional of PTYs being
> > supported?  Otherwise, this is just useless baggage, right?
> 
> Actually this should all work on Windows too, for example.

Are you sure?  The code does this, for example:

> +static FILE *
> +open_stream (const char *name)
> +{
> +  int fd;
> +
> +  fd = open (name, O_RDWR | O_NOCTTY);
> +  if (fd < 0)
> +    perror_with_name  (_("opening terminal failed"));
> +
> +  return fdopen (fd, "w+");
> +}

How do you expect this to work on Windows?  For starters, O_NOCTTY is
not supported.  And what would you use for 'name' here?  More
importantly, each Windows process can have only one console at a time,
AFAIK.

Am I missing something?

> MI doesn't really need a PTY, so even though currently the command's
> online help and git logs say usage is "new-ui INTERP TTY", that TTY part
> could actually be the name of any bidirectional stream.
> 
> E.g., it could be a bidi unix domain socket, on Linux, or on Windows,
> I think it should work to pass a console name, or a bidirectional
> named pipe path, though I haven't tried it.

There are no Unix domain sockets on Windows, AFAIK.  As for a console
name, see above.

> If necessary, it would also be easy to extend the command to support
> separate streams for in/out/err, like, e.g.:
> 
>  (gdb) new-ui INTERP IN OUT ERR
> 
> And then it'd be possible to open a new MI channel through
> unidirectional named pipes, regular files, etc. too.

But doesn't readline need a console-compatible device?  PTYs pass the
isatty test, but pipes and regular files fail it, so will readline at
all work?

I have a dreadful feeling that I'm missing something very important
here, because I'm sure I don't tell anything you don't already know.

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 17:02   ` Pedro Alves
@ 2016-03-21 17:17     ` Eli Zaretskii
  2016-03-21 17:43     ` Marc Khouzam
  1 sibling, 0 replies; 58+ messages in thread
From: Eli Zaretskii @ 2016-03-21 17:17 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, marc.khouzam

> Cc: gdb-patches@sourceware.org, marc.khouzam@ericsson.com
> From: Pedro Alves <palves@redhat.com>
> Date: Mon, 21 Mar 2016 17:02:16 +0000
> 
> On 03/21/2016 04:34 PM, Eli Zaretskii wrote:
> >> From: Pedro Alves <palves@redhat.com>
> >> Cc: Marc Khouzam <marc.khouzam@ericsson.com>
> >> Date: Mon, 21 Mar 2016 15:20:50 +0000
> >>
> >>    Add new command to create extra console/mi UI channels
> >>    Add command to list UIs
> > 
> > Are these commands intended to remain undocumented?
> 
> No, they'll absolutely be documented.  I haven't managed to write
> them documentation yet, as well as ChangeLogs, etc.  Sorry about that.

No sweat, take your time.

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

* RE: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 17:02   ` Pedro Alves
  2016-03-21 17:17     ` Eli Zaretskii
@ 2016-03-21 17:43     ` Marc Khouzam
  1 sibling, 0 replies; 58+ messages in thread
From: Marc Khouzam @ 2016-03-21 17:43 UTC (permalink / raw)
  To: Pedro Alves, Eli Zaretskii; +Cc: gdb-patches

> From: Pedro Alves [palves@redhat.com]
> Sent: March 21, 2016 1:02 PM
> To: Eli Zaretskii
> Cc: gdb-patches@sourceware.org; Marc Khouzam
> Subject: Re: [PATCH v2 00/25] Towards great frontend GDB consoles
> 
> On 03/21/2016 04:34 PM, Eli Zaretskii wrote:
> >> From: Pedro Alves <palves@redhat.com>
> >> Cc: Marc Khouzam <marc.khouzam@ericsson.com>
> >> Date: Mon, 21 Mar 2016 15:20:50 +0000
> >>
> >>    Add new command to create extra console/mi UI channels
> >>    Add command to list UIs
> >
> > Are these commands intended to remain undocumented?
> 
> No, they'll absolutely be documented.  I haven't managed to write
> them documentation yet, as well as ChangeLogs, etc.  Sorry about that.
> 
> The current state of the series is that I think it works correctly and
> that the exposed command is about what GDB should be exposing.  But experience
> with integrating it with frontends may prove otherwise. :-)  So I'm
> posting this to both try to get frontends to experiment with implementing
> support for it, and collecting feedback from the GDB side as well.  At least
> support in Eclipse is actively being worked on, though I'd think it
> great if other frontends learned to use this as well.

Sorry I haven't provide feedback yet.
I was able to demo this feature at EclipseCon and, as expected, the reaction
was very positive.  This is something we've been wanting for many years.

There are some things to workout at the frontend level which should not
impact the feature from a GDB perspective.  But there were a couple of 
small issues with GDB itself.  I will install the new series and confirm
if those issues are still present or not and will communicate back.

Thanks!

Marc

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-03-21 17:12       ` Eli Zaretskii
@ 2016-03-21 17:57         ` Pedro Alves
  2016-05-26 11:43           ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 17:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 03/21/2016 05:11 PM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org
>> From: Pedro Alves <palves@redhat.com>
>> Date: Mon, 21 Mar 2016 16:51:21 +0000
>>
>>> Shouldn't this (and other related) code be conditional of PTYs being
>>> supported?  Otherwise, this is just useless baggage, right?
>>
>> Actually this should all work on Windows too, for example.
> 
> Are you sure?  The code does this, for example:
> 
>> +static FILE *
>> +open_stream (const char *name)
>> +{
>> +  int fd;
>> +
>> +  fd = open (name, O_RDWR | O_NOCTTY);
>> +  if (fd < 0)
>> +    perror_with_name  (_("opening terminal failed"));
>> +
>> +  return fdopen (fd, "w+");
>> +}
> 
> How do you expect this to work on Windows?  For starters, O_NOCTTY is
> not supported. 

I thought I had tried building this on Windows, looks like not.
I was misled by this bit in windows-nat.c:

      tty = open (inferior_io_terminal, O_RDWR | O_NOCTTY);

but I see now that that's Cygwin only.

inflow.c has this at the top:

#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif

guess I'll do the same here.

> And what would you use for 'name' here?  More
> importantly, each Windows process can have only one console at a time,
> AFAIK.
> 
> Am I missing something?

Hmm, I thought you could create multiple Windows consoles in a process,
but I now see you can't unless you detach from the previous console:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682528%28v=vs.85%29.aspx

I imagine it should be possible to start GDB in MI mode, with
no console attached, and then do "new-ui console con1:" and have
gdb attach to that console.  Since there'd be only one CLI instance
inside gdb when run like this, we could support line editing / readline 
on this secondary UI, though we don't, not yet.  That would require 
more work, on GNU/Linux too.  FAOD, it does work to start gdb in MI and
create a secondary CLI UI, but it'll not have readline active (it works
as if you started gdb with isatty(0)==0, or with "set editing off").

But the way I see it working is that the frontend creates a bidirectional
named pipe, with CreateNamedPipe(PIPE_ACCESS_DUPLEX), for MI communication.
Then it starts GDB in console mode, attached to a real console window
embedded in the frontend's GUI (*) and tells gdb to open the MI ui on the
named pipe.  Like:

 $ gdb -q -ex "new-ui mi \\.\pipe\pipename"

I _think_ that should work, but it's been years since I did
anything closely related on Windows.

* - years ago when I had to use Windows on a regular basis, I used
the Console2 program, which has multiple console windows, though
I don't know exact details of how.  Maybe some multi-process trick.

> 
>> MI doesn't really need a PTY, so even though currently the command's
>> online help and git logs say usage is "new-ui INTERP TTY", that TTY part
>> could actually be the name of any bidirectional stream.
>>
>> E.g., it could be a bidi unix domain socket, on Linux, or on Windows,
>> I think it should work to pass a console name, or a bidirectional
>> named pipe path, though I haven't tried it.
> 
> There are no Unix domain sockets on Windows, AFAIK.  As for a console
> name, see above.

There are bidirectional named pipes though.

> 
>> If necessary, it would also be easy to extend the command to support
>> separate streams for in/out/err, like, e.g.:
>>
>>   (gdb) new-ui INTERP IN OUT ERR
>>
>> And then it'd be possible to open a new MI channel through
>> unidirectional named pipes, regular files, etc. too.
> 
> But doesn't readline need a console-compatible device?  PTYs pass the
> isatty test, but pipes and regular files fail it, so will readline at
> all work?

You'll normally be specifying "MI" as INTERP, which does not need to
 use readline at all.  So as mentioned above, a frontend first starts GDB
in console mode, with stdin/stdout/stderr associated with a PTY/console,
and then opens a secondary ui with "new-ui" for MI.  And this MI ui does
_not_ need to pass the isatty test, as MI does not really need a terminal
for anything.

> I have a dreadful feeling that I'm missing something very important
> here, because I'm sure I don't tell anything you don't already know.

Thanks,
Pedro Alves

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

* RE: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (25 preceding siblings ...)
  2016-03-21 16:34 ` [PATCH v2 00/25] Towards great frontend GDB consoles Eli Zaretskii
@ 2016-03-21 18:35 ` Marc Khouzam
  2016-03-21 18:51   ` Pedro Alves
  2016-03-22 10:41 ` Yao Qi
  27 siblings, 1 reply; 58+ messages in thread
From: Marc Khouzam @ 2016-03-21 18:35 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

> From: Pedro Alves [palves@redhat.com]
> Sent: March 21, 2016 11:20 AM
> To: gdb-patches@sourceware.org
> Cc: Marc Khouzam
> Subject: [PATCH v2 00/25] Towards great frontend GDB consoles
> 
> Here's an update of the series I first posted here:
>   https://sourceware.org/ml/gdb-patches/2016-02/msg00067.html
> 
> New in v2:
> 
> - The "Command line input handling TLC" patch [1] has since been split
>   into a series of its own [2], and pushed in.
> 
>   [1] https://sourceware.org/ml/gdb-patches/2016-02/msg00070.html
>   [2] https://sourceware.org/ml/gdb-patches/2016-02/msg00557.html
> 
> - Currently, if GDB's (main) stdin closes, GDB exits.  That logic
>   carried over to secondary UIs as well, by mistake, so v1, if a
>   secondary UI's terminal was closed, GDB would just exit as well...
>   In v2, that's now detected, and GDB just discards the UI.
> 
> - I noticed that if you typed something in a secondary UI, and then
>   Ctrl-C'd the main UI, GDB would internal error.  The problem was
>   that nothing was making use async signal handlers (in this case,
>   async_request_quit) always run on the main UI.
> 
> - Added a convenience "info uis" command to list UIs.
> 
> - Some cleanups here and there
> 
> Force-pushed to users/palves/console at sourceware.org.

From the previous testing I did, and from the demo I gave,
your previous patches were already of very good quality.
Thank you for those.

Right now, there are only three issues that I can report.
They are present in v2.

1- The new-ui command should not be a repeating command

2- Using 'interpreter-exec mi" in the CLI console confuses GDB
   To reproduce from a shell
   - start GDB in CLI mode
   - give a "new-ui mi" command to start an MI channel
   - start running the inferior => *stopped/*running events are on the MI channel
   - in the CLI send command interpreter-exec mi ""
   - step or resume
   => *stopped/*running events are now on the CLI channel and not the MI one

3- Issues when using "set inferior-tty"
   To reproduce from a shell
   - start GDB in CLI mode
   - give a "new-ui mi" command to start an MI channel
   - use "set inferior-tty" to another tty (like eclipse does)
   - in the MI channel, use -exec-run
   => the shell where GDB CLI is running no longer responds to input

Feel free to ask for any clarifications.

I'll be doing some more thorough testing using this feature with Eclipse, as the integration
is almost done.  I'll communicate any other issues I find.

Thanks again!

Marc

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 18:35 ` Marc Khouzam
@ 2016-03-21 18:51   ` Pedro Alves
  2016-03-21 19:06     ` Marc Khouzam
  2016-05-06 12:58     ` Pedro Alves
  0 siblings, 2 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 18:51 UTC (permalink / raw)
  To: Marc Khouzam, gdb-patches

On 03/21/2016 06:34 PM, Marc Khouzam wrote:
>> From: Pedro Alves [palves@redhat.com]
>> Sent: March 21, 2016 11:20 AM
>> To: gdb-patches@sourceware.org
>> Cc: Marc Khouzam
>> Subject: [PATCH v2 00/25] Towards great frontend GDB consoles
>>
>> Here's an update of the series I first posted here:
>>    https://sourceware.org/ml/gdb-patches/2016-02/msg00067.html
>>
>> New in v2:
>>
>> - The "Command line input handling TLC" patch [1] has since been split
>>    into a series of its own [2], and pushed in.
>>
>>    [1] https://sourceware.org/ml/gdb-patches/2016-02/msg00070.html
>>    [2] https://sourceware.org/ml/gdb-patches/2016-02/msg00557.html
>>
>> - Currently, if GDB's (main) stdin closes, GDB exits.  That logic
>>    carried over to secondary UIs as well, by mistake, so v1, if a
>>    secondary UI's terminal was closed, GDB would just exit as well...
>>    In v2, that's now detected, and GDB just discards the UI.
>>
>> - I noticed that if you typed something in a secondary UI, and then
>>    Ctrl-C'd the main UI, GDB would internal error.  The problem was
>>    that nothing was making use async signal handlers (in this case,
>>    async_request_quit) always run on the main UI.
>>
>> - Added a convenience "info uis" command to list UIs.
>>
>> - Some cleanups here and there
>>
>> Force-pushed to users/palves/console at sourceware.org.
> 
>  From the previous testing I did, and from the demo I gave,
> your previous patches were already of very good quality.
> Thank you for those.
> 

Glad to hear that!  Sounds like we're not that far off then.

> Right now, there are only three issues that I can report.
> They are present in v2.
> 
> 1- The new-ui command should not be a repeating command

Indeed.

> 2- Using 'interpreter-exec mi" in the CLI console confuses GDB
>     To reproduce from a shell
>     - start GDB in CLI mode
>     - give a "new-ui mi" command to start an MI channel
>     - start running the inferior => *stopped/*running events are on the MI channel
>     - in the CLI send command interpreter-exec mi ""
>     - step or resume
>     => *stopped/*running events are now on the CLI channel and not the MI one

I can reproduce this.

This may be related to the fact that MI's code still has a bunch of
globals that I hadn't made per-UI, thinking that that would be sufficient
for the use case at hand.  While annoying, I wouldn't expect a
regular user / script to be issuing MI commands, right?

> 
> 3- Issues when using "set inferior-tty"
>     To reproduce from a shell
>     - start GDB in CLI mode
>     - give a "new-ui mi" command to start an MI channel
>     - use "set inferior-tty" to another tty (like eclipse does)
>     - in the MI channel, use -exec-run
>     => the shell where GDB CLI is running no longer responds to input

Interesting.  I can reproduce this as well.  I wonder if it's 
related to PR gdb/18077 (-exec-run results in synchronous execution),
but then again, it doesn't reproduce without "set inferior-tty".

> 
> Feel free to ask for any clarifications.
> 
> I'll be doing some more thorough testing using this feature with Eclipse, as the integration
> is almost done.  I'll communicate any other issues I find.
> 
> Thanks again!

Thanks for the feedback!

-- 
Pedro Alves

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

* RE: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 18:51   ` Pedro Alves
@ 2016-03-21 19:06     ` Marc Khouzam
  2016-03-21 19:12       ` Pedro Alves
  2016-05-06 12:58     ` Pedro Alves
  1 sibling, 1 reply; 58+ messages in thread
From: Marc Khouzam @ 2016-03-21 19:06 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

> ________________________________________
> From: Pedro Alves [palves@redhat.com]
> Sent: March 21, 2016 2:51 PM
> To: Marc Khouzam; gdb-patches@sourceware.org
> Subject: Re: [PATCH v2 00/25] Towards great frontend GDB consoles
> 
> On 03/21/2016 06:34 PM, Marc Khouzam wrote:
> >> From: Pedro Alves [palves@redhat.com]
> >> Sent: March 21, 2016 11:20 AM
> >> To: gdb-patches@sourceware.org
> >> Cc: Marc Khouzam
> >> Subject: [PATCH v2 00/25] Towards great frontend GDB consoles
> >>
> >> Here's an update of the series I first posted here:
> >>    https://sourceware.org/ml/gdb-patches/2016-02/msg00067.html
> >>
> >> New in v2:
> >>
> >> - The "Command line input handling TLC" patch [1] has since been split
> >>    into a series of its own [2], and pushed in.
> >>
> >>    [1] https://sourceware.org/ml/gdb-patches/2016-02/msg00070.html
> >>    [2] https://sourceware.org/ml/gdb-patches/2016-02/msg00557.html
> >>
> >> - Currently, if GDB's (main) stdin closes, GDB exits.  That logic
> >>    carried over to secondary UIs as well, by mistake, so v1, if a
> >>    secondary UI's terminal was closed, GDB would just exit as well...
> >>    In v2, that's now detected, and GDB just discards the UI.
> >>
> >> - I noticed that if you typed something in a secondary UI, and then
> >>    Ctrl-C'd the main UI, GDB would internal error.  The problem was
> >>    that nothing was making use async signal handlers (in this case,
> >>    async_request_quit) always run on the main UI.
> >>
> >> - Added a convenience "info uis" command to list UIs.
> >>
> >> - Some cleanups here and there
> >>
> >> Force-pushed to users/palves/console at sourceware.org.
> >
> >  From the previous testing I did, and from the demo I gave,
> > your previous patches were already of very good quality.
> > Thank you for those.
> >
> 
> Glad to hear that!  Sounds like we're not that far off then.
> 
> > Right now, there are only three issues that I can report.
> > They are present in v2.
> >
> > 1- The new-ui command should not be a repeating command
> 
> Indeed.
> 
> > 2- Using 'interpreter-exec mi" in the CLI console confuses GDB
> >     To reproduce from a shell
> >     - start GDB in CLI mode
> >     - give a "new-ui mi" command to start an MI channel
> >     - start running the inferior => *stopped/*running events are on the MI channel
> >     - in the CLI send command interpreter-exec mi ""
> >     - step or resume
> >     => *stopped/*running events are now on the CLI channel and not the MI one
> 
> I can reproduce this.
> 
> This may be related to the fact that MI's code still has a bunch of
> globals that I hadn't made per-UI, thinking that that would be sufficient
> for the use case at hand.  While annoying, I wouldn't expect a
> regular user / script to be issuing MI commands, right?

Yes, I guess I'm one of the rare people that use interpreter-exe mi :)
So, making this work is not urgent at all.  But I am a little worried that
if the user does issue such a command, the eclipse session stops
working (as it misses the MI events).  Would it be hard to disable
the problematic command when 'new-ui' has been used?

> > 3- Issues when using "set inferior-tty"
> >     To reproduce from a shell
> >     - start GDB in CLI mode
> >     - give a "new-ui mi" command to start an MI channel
> >     - use "set inferior-tty" to another tty (like eclipse does)
> >     - in the MI channel, use -exec-run
> >     => the shell where GDB CLI is running no longer responds to input
> 
> Interesting.  I can reproduce this as well.  I wonder if it's
> related to PR gdb/18077 (-exec-run results in synchronous execution),
> but then again, it doesn't reproduce without "set inferior-tty".
> 
> >
> > Feel free to ask for any clarifications.
> >
> > I'll be doing some more thorough testing using this feature with Eclipse, as the integration
> > is almost done.  I'll communicate any other issues I find.
> >
> > Thanks again!
> 
> Thanks for the feedback!
> 
> --
> Pedro Alves

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 19:06     ` Marc Khouzam
@ 2016-03-21 19:12       ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-03-21 19:12 UTC (permalink / raw)
  To: Marc Khouzam, gdb-patches

On 03/21/2016 07:06 PM, Marc Khouzam wrote:

>> From: Pedro Alves [palves@redhat.com]

>>> 2- Using 'interpreter-exec mi" in the CLI console confuses GDB
>>>      To reproduce from a shell
>>>      - start GDB in CLI mode
>>>      - give a "new-ui mi" command to start an MI channel
>>>      - start running the inferior => *stopped/*running events are on the MI channel
>>>      - in the CLI send command interpreter-exec mi ""
>>>      - step or resume
>>>      => *stopped/*running events are now on the CLI channel and not the MI one
>>
>> I can reproduce this.
>>
>> This may be related to the fact that MI's code still has a bunch of
>> globals that I hadn't made per-UI, thinking that that would be sufficient
>> for the use case at hand.  While annoying, I wouldn't expect a
>> regular user / script to be issuing MI commands, right?
> 
> Yes, I guess I'm one of the rare people that use interpreter-exe mi :)

:-)

> So, making this work is not urgent at all.  But I am a little worried that
> if the user does issue such a command, the eclipse session stops
> working (as it misses the MI events).  

Indeed.

> Would it be hard to disable
> the problematic command when 'new-ui' has been used?

Hmm, probably not.  I don't know yet whether it'd be hard to
fix properly, but I'll take a look first before taking that route.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 04/25] Introduce interpreter factories
  2016-03-21 15:29 ` [PATCH v2 04/25] Introduce interpreter factories Pedro Alves
@ 2016-03-22  8:55   ` Yao Qi
  2016-05-06 11:49     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22  8:55 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves <palves@redhat.com> writes:

> +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);
> +}

It shouldn't be hard to do the assert here, and get rid of the FIXME.

-- 
Yao (齐尧)

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

* Re: [PATCH v2 05/25] Make the intepreters output to all UIs
  2016-03-21 15:29 ` [PATCH v2 05/25] Make the intepreters output to all UIs Pedro Alves
@ 2016-03-22  9:33   ` Yao Qi
  2016-05-06 12:19     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22  9:33 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves <palves@redhat.com> writes:

Hi Pedro,
We have three interpreters, cli, mi and tui.  Each of them has a
${inter}_on_normal_stop registered to normal_stop observer, as below,

> @@ -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);
>      }
>  }
>  

>  
>  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
>  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));
>      }
>  }

Why don't we have 'struct ui' have a method 'print_stop_event', so that
we can put the different handling there.  In this way, we can only
register one to normal_stop observer, in interps.c for example, and the
code can be simplified, like this,

static void
interp_on_normal_stop (struct bpstats *bs, int print_frame)
{
  struct switch_thru_all_uis state;

  SWITCH_THRU_ALL_UIS (state)
    {
       current_ui->print_stop_event (bs, print_frame);
    }
}

we don't have to check the type of interpreter in the loop anymore.

-- 
Yao (齐尧)

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

* Re: [PATCH v2 08/25] Make input_fd be per UI
  2016-03-21 15:26 ` [PATCH v2 08/25] Make input_fd be per UI Pedro Alves
@ 2016-03-22  9:46   ` Yao Qi
  2016-05-06 11:53     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22  9:46 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves <palves@redhat.com> writes:

> @@ -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;

We should call add_file_handler after the terminal_state check above.

-- 
Yao (齐尧)

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

* Re: [PATCH v2 22/25] Make main_ui be heap allocated
  2016-03-21 15:21 ` [PATCH v2 22/25] Make main_ui be heap allocated Pedro Alves
@ 2016-03-22 10:14   ` Yao Qi
  2016-05-06 11:50     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22 10:14 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves <palves@redhat.com> writes:

> ---
>  gdb/event-top.c |  7 +++----
>  gdb/main.c      | 27 ++++++++++++---------------
>  gdb/top.c       | 37 +++++++++++++++++++++++++++++++++++++
>  gdb/top.h       |  5 +++++
>  4 files changed, 57 insertions(+), 19 deletions(-)
>
> diff --git a/gdb/event-top.c b/gdb/event-top.c
> index 436edf7..69f6be7 100644
> --- a/gdb/event-top.c
> +++ b/gdb/event-top.c
> @@ -362,11 +362,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;

We need comments to "main_ui" and "current_ui".  I am carrying a
question "what is the main UI" since patch 06.

-- 
Yao (齐尧)

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

* Re: [PATCH v2 13/25] Always process target events in the main UI
  2016-03-21 15:22 ` [PATCH v2 13/25] Always process target events in the main UI Pedro Alves
@ 2016-03-22 10:26   ` Yao Qi
  2016-05-06 11:53     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22 10:26 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves <palves@redhat.com> writes:

> 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.

Anything wrong if we don't do so?  In patch 08, current_ui is switched
to right ui if something is typed in from that ui, isn't good to process
events in that ui as well?  say, I type some commands in one ui, and I
expect the output go to my ui rather than the main one.

-- 
Yao (齐尧)

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

* Re: [PATCH v2 25/25] Add command to list UIs
  2016-03-21 15:30 ` [PATCH v2 25/25] Add command to list UIs Pedro Alves
@ 2016-03-22 10:36   ` Yao Qi
  2016-05-06 11:49     ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22 10:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves <palves@redhat.com> writes:

> @@ -368,6 +368,7 @@ new_ui_command (char *args, int from_tty)
>  
>    initialize_stdin_serial (ui);
>    ui->async = 1;
> +  ui->tty_name = xstrdup (tty_name);

xfree (ui->tty_name) in free_ui?

-- 
Yao (齐尧)

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
                   ` (26 preceding siblings ...)
  2016-03-21 18:35 ` Marc Khouzam
@ 2016-03-22 10:41 ` Yao Qi
  2016-05-06 11:58   ` Pedro Alves
  27 siblings, 1 reply; 58+ messages in thread
From: Yao Qi @ 2016-03-22 10:41 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Marc Khouzam

Pedro Alves <palves@redhat.com> writes:

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

I go through the patches, and give my comments.  They look pretty good!
We need to think about the tests.

-- 
Yao (齐尧)

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

* Re: [PATCH v2 04/25] Introduce interpreter factories
  2016-03-22  8:55   ` Yao Qi
@ 2016-05-06 11:49     ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 11:49 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

Finally getting back to this...

On 03/22/2016 08:55 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> +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);
>> +}
> 
> It shouldn't be hard to do the assert here, and get rid of the FIXME.
> 

Indeed.  I fixed this for v3.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 25/25] Add command to list UIs
  2016-03-22 10:36   ` Yao Qi
@ 2016-05-06 11:49     ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 11:49 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 03/22/2016 10:36 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> @@ -368,6 +368,7 @@ new_ui_command (char *args, int from_tty)
>>  
>>    initialize_stdin_serial (ui);
>>    ui->async = 1;
>> +  ui->tty_name = xstrdup (tty_name);
> 
> xfree (ui->tty_name) in free_ui?

Indeed, thanks.

I'm still not sure whether this command's output format is the one
we need, and this was mostly a convenience for developing the series,
so I'm dropping it from the series in v3, and will get back to it
afterwards.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 22/25] Make main_ui be heap allocated
  2016-03-22 10:14   ` Yao Qi
@ 2016-05-06 11:50     ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 11:50 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 03/22/2016 10:14 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> ---
>>  gdb/event-top.c |  7 +++----
>>  gdb/main.c      | 27 ++++++++++++---------------
>>  gdb/top.c       | 37 +++++++++++++++++++++++++++++++++++++
>>  gdb/top.h       |  5 +++++
>>  4 files changed, 57 insertions(+), 19 deletions(-)
>>
>> diff --git a/gdb/event-top.c b/gdb/event-top.c
>> index 436edf7..69f6be7 100644
>> --- a/gdb/event-top.c
>> +++ b/gdb/event-top.c
>> @@ -362,11 +362,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;
> 
> We need comments to "main_ui" and "current_ui".  I am carrying a
> question "what is the main UI" since patch 06.

Good point.  I've added comments in v3.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 13/25] Always process target events in the main UI
  2016-03-22 10:26   ` Yao Qi
@ 2016-05-06 11:53     ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 11:53 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 03/22/2016 10:26 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> 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.
> 
> Anything wrong if we don't do so?  In patch 08, current_ui is switched
> to right ui if something is typed in from that ui, isn't good to process
> events in that ui as well?  say, I type some commands in one ui, and I
> expect the output go to my ui rather than the main one.

The problem is that there's no connection at all between an asynchronous
target event and "that" command that you mention.  There may even not
be a command at all.  E.g., say do you do "continue&" in UI 2, and then
the program spawns threads, etc.  And then you type something in
UI 3 (current UI is now 3), for example, switch to another inferior "run &"
it.  Consider that UI 4 may be the MI channel, and the frontend
sends MI commands meanwhile as well, thus switching the current UI too.
All the while, some random thread hits some internal event that happens
to trigger some warning deep down inside symbol reading or some such.
Where should the warning go?  What if an internal error triggers?  Where
should we present the query?  Or any other query, for the matter?
Since it's indeterminate which is the best UI channel, best is to
define it as defaulting to the main console.

A similar issue happens with where e.g., "set debug infrun 1" output goes.
If we don't force-default to the main UI, then output for random asynchronous
events ends up going to whatever UI gdb internally happened to last switch
to, which is an internal implementation detail.  (Usually it'll be the last
UI you typed in).  Again in this case, I think we need to default to
the main console/UI, and then come up with something specialized for
debug output.  Currently we do:

 if (debug_foo)
   fprintf_unfiltered (gdb_stdlog, ...);

 if (debug_bar)
   fprintf_unfiltered (gdb_stdlog, ...);

which sends output to the current UI's gdb_stdlog.  But we may
want to say that "debug_foo" goes to UI 1, and "debug_bar" goes
to UI 2.  For example, because "set debug foo 1" was activated
in UI 1, and "set debug bar" was activated in UI 2.  This suggests
reworking the debug APIs to have one stream object per debug setting,
I think.  Obviously, I'd rather not do this as requirement for this
series.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 08/25] Make input_fd be per UI
  2016-03-22  9:46   ` Yao Qi
@ 2016-05-06 11:53     ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 11:53 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 03/22/2016 09:46 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> @@ -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;
> 
> We should call add_file_handler after the terminal_state check above.
> 

We actually shouldn't, because terminal_state only refers to the
state of gdb's main tty state, while we still want to add/remove
the _current_ UI's input_fd from the event loop.   I've added
comments in v3.

Note that I'm gradually bubbling up these input_fd calls from the
targets backends towards common code.  At some point I'd like to
migrate them somewhere even higher, maybe merged with
async_disable_stdin / async_enable_stdin, now that since the ctrl-c
rework series we only call target_terminal_ours when we really need
input.  But that'll be yet another set of
cleaning-up-all-over-the-tree that I'd much rather not do
along with this series.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-22 10:41 ` Yao Qi
@ 2016-05-06 11:58   ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 11:58 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches, Marc Khouzam

On 03/22/2016 10:41 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
>> This still misses ChangeLog entries, some comments, and documentation
>> changes.  And I haven't thought about tests yet.
> 
> I go through the patches, and give my comments.  

Thanks much!

> They look pretty good!
> We need to think about the tests.

So for v3, I added a way to run the whole testsuite with
MI running in a separate UI, by passing:

 make check RUNTESTFLAGS="FORCE_SEPARATE_MI_TTY=1"

That was quite convenient and caught a few issues, all of
which I resolved for v3.

In addition, I made it possible for the tests themselves
to easily start with MI on a separate UI.  So some of the
new patches in v3 come changes to testcases to make them
run with both MI running in the main UI and as separate UI.

All in all, I'm pretty confident with v3 now.  I'll post it
soon.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 05/25] Make the intepreters output to all UIs
  2016-03-22  9:33   ` Yao Qi
@ 2016-05-06 12:19     ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 12:19 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 03/22/2016 09:33 AM, Yao Qi wrote:
> Pedro Alves <palves@redhat.com> writes:
> 
> Hi Pedro,
> We have three interpreters, cli, mi and tui.  Each of them has a
> ${inter}_on_normal_stop registered to normal_stop observer, as below,
> 
> Why don't we have 'struct ui' have a method 'print_stop_event', so that
> we can put the different handling there.

That's what I tried in an earlier attempt as I tried to describe in
the commit log:

    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.

I have an earlier version of the series on my github that goes all
the way to make it possible to have multiple independent TUIs active.
And then the TUI has even more random observers.  It turned out to be
a huge mess.

So even though this particular observer could seemingly be handled
like that, there's a larger pattern here that applies to all
observers all interpreters use.

I think that if we do switch to the mechanism of calling a
"virtual" method directly, it'll be by calling into the
method on the UI's top level interpreter directly.

A wrinkle is that some interpreters install an observer than
works with the current interpreter, while others install an
observer that works with the top level interpreter.  That should
probably be changed to always dispatch through the top level
interpreter.  I tried that too, but, it was getting unwildly,
and decided to back off.  Yet another large-ish change for another
day.  I suspect it'll be easier in C++.

But even that isn't clear to me is the best approach.  The
lose coupling between common code and the interpreters provided
by the observers is quite convenient.  I think of it as the
common code posting an event, and then the interpreters consuming
it.  I thought of making it possible to associate a "data" pointer
with each observer, thus have each UI instance register itself
as an observer for a particular event, instead of registering
an observer for the whole set of UI instances of a type of UI
and then have each observer iterate over all instances.
But then that would be painful to do with the current observers
design, it'd much much more natural in C++11 with lambdas or
some such...

>  In this way, we can only
> register one to normal_stop observer, in interps.c for example, and the
> code can be simplified, like this,
> 
> static void
> interp_on_normal_stop (struct bpstats *bs, int print_frame)
> {
>   struct switch_thru_all_uis state;
> 
>   SWITCH_THRU_ALL_UIS (state)
>     {
>        current_ui->print_stop_event (bs, print_frame);
>     }
> }
> 
> we don't have to check the type of interpreter in the loop anymore.
> 

I'd much prefer to go the direction of calling into the top interpreter,
instead of adding virtual methods to the UI:

   SWITCH_THRU_ALL_UIS (state)
     {
        current_ui->top_level_interpreter->print_stop_event (bs, print_frame);
     }

Because an UI has-a interpreter, not is-a one.

But I've tried this, and ended up with too-ugly template-like
macros and too much boilerplace, and lots of duplication in
in UI's interface, and I never managed to make it regression free.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 00/25] Towards great frontend GDB consoles
  2016-03-21 18:51   ` Pedro Alves
  2016-03-21 19:06     ` Marc Khouzam
@ 2016-05-06 12:58     ` Pedro Alves
  1 sibling, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-06 12:58 UTC (permalink / raw)
  To: Marc Khouzam, gdb-patches

On 03/21/2016 06:51 PM, Pedro Alves wrote:
> 
>> > 2- Using 'interpreter-exec mi" in the CLI console confuses GDB
>> >     To reproduce from a shell
>> >     - start GDB in CLI mode
>> >     - give a "new-ui mi" command to start an MI channel
>> >     - start running the inferior => *stopped/*running events are on the MI channel
>> >     - in the CLI send command interpreter-exec mi ""
>> >     - step or resume
>> >     => *stopped/*running events are now on the CLI channel and not the MI one
> I can reproduce this.
> 
> This may be related to the fact that MI's code still has a bunch of
> globals that I hadn't made per-UI, thinking that that would be sufficient
> for the use case at hand.  While annoying, I wouldn't expect a
> regular user / script to be issuing MI commands, right?

For the record, this was indeed related to MI globals.  Specifically,
"raw_stdout".  Fixed by making it be per-MI instead:

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

>> > 
>> > 3- Issues when using "set inferior-tty"
>> >     To reproduce from a shell
>> >     - start GDB in CLI mode
>> >     - give a "new-ui mi" command to start an MI channel
>> >     - use "set inferior-tty" to another tty (like eclipse does)
>> >     - in the MI channel, use -exec-run
>> >     => the shell where GDB CLI is running no longer responds to input
> Interesting.  I can reproduce this as well.  I wonder if it's 
> related to PR gdb/18077 (-exec-run results in synchronous execution),
> but then again, it doesn't reproduce without "set inferior-tty".

This was related to an issue with how gdb starts inferiors.  It
vforks, then uses ptrace (PTRACE_ME), and then execs.  Between
the vfork and the exec, the child was running with the MI channel
as current UI, and because it's a vfork, that messed up the
parent gdb's structures.  Fixed here, with a testcase that
ensures that "set inferior-tty" use cases are correctly handled:

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

Thanks,
Pedro Alves

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-03-21 17:57         ` Pedro Alves
@ 2016-05-26 11:43           ` Pedro Alves
  2016-05-26 15:46             ` Eli Zaretskii
  0 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-05-26 11:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 03/21/2016 05:57 PM, Pedro Alves wrote:
> On 03/21/2016 05:11 PM, Eli Zaretskii wrote:

> 
>>
>>> If necessary, it would also be easy to extend the command to support
>>> separate streams for in/out/err, like, e.g.:
>>>
>>>   (gdb) new-ui INTERP IN OUT ERR
>>>
>>> And then it'd be possible to open a new MI channel through
>>> unidirectional named pipes, regular files, etc. too.
>>
>> But doesn't readline need a console-compatible device?  PTYs pass the
>> isatty test, but pipes and regular files fail it, so will readline at
>> all work?
> 
> You'll normally be specifying "MI" as INTERP, which does not need to
>  use readline at all.  So as mentioned above, a frontend first starts GDB
> in console mode, with stdin/stdout/stderr associated with a PTY/console,
> and then opens a secondary ui with "new-ui" for MI.  And this MI ui does
> _not_ need to pass the isatty test, as MI does not really need a terminal
> for anything.
> 

I've been thinking a bit on how to make this all work on Windows,
with Eclipse, and my current thinking is that instead of some hack to 
embed a native console window inside the GUI, better would be to reuse 
the same Eclipse terminal emulator widget, and coax gdb
to send the right terminal escape sequences for cursor movement
and character placement as a Unix gdb would.

Instead of a pty, that terminal widget would be backed by a bidirectional
named pipe.  Cygwin ptys use that behind the scenes as well.

So in the end, GDB would be running with input/output connected to a
named pipe, and we'd need to force gdb and ncurses to believe that
that is a terminal.

I'm aware that GNU ncurses, has a concept of "drivers", and it
has a driver for real windows consoles ("win32con") and that is
the default.  AFAIK, the way to select the driver is to set
the TERM env var.

So in theory, all one would need to do is to set the TERM env
var to vt100, xterm, or some such to force the right driver.

The problems will probably be around isatty checks in
readline and ncurses, as you suggested.

There may also be #ifdef WIN32 bits in those libraries that
are #ifdef-ing out code that we'll need, assuming terminal == console,
though I haven't really checked.

The isatty problem looks very much like the problem a native Windows/mingw
program has when run on a Cygwin terminal (and MSYS/MSYS2, which are
Cygwin forks), since Cygwin emulates pseudo terminals via named pipes.
See, e.g.,:

  http://www.spinics.net/lists/git/msg274348.html

So I think it should be possible to make it work on Windows, and I
think it's the right way forward, though some further
ncurses/readline/gdb patching might be in order.

So it looks like if you get native Windows GDB (readline/ncurses)
behaving correctly (history, completion, etc.) when run on a Cygwin
terminal, then from within Eclipse or any other GUI, it would
work as well.

BTW, while investigating this, I found that since some recent
update to Windows 10, Windows consoles now supports ansi/vt100
escape sequences, finally:

 http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements

This further reinforces to me the idea of using ansi escapes on
Windows Eclipse/gdb too.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-05-26 11:43           ` Pedro Alves
@ 2016-05-26 15:46             ` Eli Zaretskii
  2016-05-26 16:03               ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Eli Zaretskii @ 2016-05-26 15:46 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 26 May 2016 12:43:01 +0100
> 
> I've been thinking a bit on how to make this all work on Windows,
> with Eclipse, and my current thinking is that instead of some hack to 
> embed a native console window inside the GUI, better would be to reuse 
> the same Eclipse terminal emulator widget, and coax gdb
> to send the right terminal escape sequences for cursor movement
> and character placement as a Unix gdb would.

Sorry, I know nothing about this "Eclipse terminal emulator widget".

In any case, this is Eclipse-specific, right?

> So in the end, GDB would be running with input/output connected to a
> named pipe, and we'd need to force gdb and ncurses to believe that
> that is a terminal.

I'm quite sure this would be a lot of work.

> I'm aware that GNU ncurses, has a concept of "drivers", and it
> has a driver for real windows consoles ("win32con") and that is
> the default.  AFAIK, the way to select the driver is to set
> the TERM env var.

To select a different driver?  Yes, the default is only used if TERM
is unset.

> The problems will probably be around isatty checks in
> readline and ncurses, as you suggested.
> 
> There may also be #ifdef WIN32 bits in those libraries that
> are #ifdef-ing out code that we'll need, assuming terminal == console,
> though I haven't really checked.

Right.

> The isatty problem looks very much like the problem a native Windows/mingw
> program has when run on a Cygwin terminal (and MSYS/MSYS2, which are
> Cygwin forks), since Cygwin emulates pseudo terminals via named pipes.
> See, e.g.,:
> 
>   http://www.spinics.net/lists/git/msg274348.html

Cygwin also owns the libc it uses, so it's easy to work around the
related problems.  MinGW cannot do that easily.

> BTW, while investigating this, I found that since some recent
> update to Windows 10, Windows consoles now supports ansi/vt100
> escape sequences, finally:
> 
>  http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements
> 
> This further reinforces to me the idea of using ansi escapes on
> Windows Eclipse/gdb too.

Not sure how that is related, since the emulator is not a console for
the program that runs on it.

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-05-26 15:46             ` Eli Zaretskii
@ 2016-05-26 16:03               ` Pedro Alves
  2016-05-26 16:36                 ` Eli Zaretskii
  0 siblings, 1 reply; 58+ messages in thread
From: Pedro Alves @ 2016-05-26 16:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 05/26/2016 04:46 PM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org
>> From: Pedro Alves <palves@redhat.com>
>> Date: Thu, 26 May 2016 12:43:01 +0100
>>
>> I've been thinking a bit on how to make this all work on Windows,
>> with Eclipse, and my current thinking is that instead of some hack to 
>> embed a native console window inside the GUI, better would be to reuse 
>> the same Eclipse terminal emulator widget, and coax gdb
>> to send the right terminal escape sequences for cursor movement
>> and character placement as a Unix gdb would.
> 
> Sorry, I know nothing about this "Eclipse terminal emulator widget".

Just think of it as a terminal emulator, like xterm or any other.

> 
> In any case, this is Eclipse-specific, right?

Other frontends will probably follow the same approach.

>> The problems will probably be around isatty checks in
>> readline and ncurses, as you suggested.
>>
>> There may also be #ifdef WIN32 bits in those libraries that
>> are #ifdef-ing out code that we'll need, assuming terminal == console,
>> though I haven't really checked.
> 
> Right.
> 
>> The isatty problem looks very much like the problem a native Windows/mingw
>> program has when run on a Cygwin terminal (and MSYS/MSYS2, which are
>> Cygwin forks), since Cygwin emulates pseudo terminals via named pipes.
>> See, e.g.,:
>>
>>   http://www.spinics.net/lists/git/msg274348.html
> 
> Cygwin also owns the libc it uses, so it's easy to work around the
> related problems.  MinGW cannot do that easily.

I think you misunderstand.  That patch is against a native mingw program
(git mingw port).  The patch is a clever hack that makes msvcrt's "isatty"
return true when input/output is connected to a named pipe that has a name
that is recognized as being a MSYS pty.

> 
>> BTW, while investigating this, I found that since some recent
>> update to Windows 10, Windows consoles now supports ansi/vt100
>> escape sequences, finally:
>>
>>  http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements
>>
>> This further reinforces to me the idea of using ansi escapes on
>> Windows Eclipse/gdb too.
> 
> Not sure how that is related, since the emulator is not a console for
> the program that runs on it.

I mean that going forward, with that, it won't sound so strange for 
native Windows console applications to output ansi escape sequences
instead of using the console APIs to control cursor positioning, etc.

Thanks,
Pedro Alves

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-05-26 16:03               ` Pedro Alves
@ 2016-05-26 16:36                 ` Eli Zaretskii
  2016-05-26 16:41                   ` Pedro Alves
  0 siblings, 1 reply; 58+ messages in thread
From: Eli Zaretskii @ 2016-05-26 16:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> Cc: gdb-patches@sourceware.org
> From: Pedro Alves <palves@redhat.com>
> Date: Thu, 26 May 2016 17:03:33 +0100
> 
> >> BTW, while investigating this, I found that since some recent
> >> update to Windows 10, Windows consoles now supports ansi/vt100
> >> escape sequences, finally:
> >>
> >>  http://www.nivot.org/blog/post/2016/02/04/Windows-10-TH2-%28v1511%29-Console-Host-Enhancements
> >>
> >> This further reinforces to me the idea of using ansi escapes on
> >> Windows Eclipse/gdb too.
> > 
> > Not sure how that is related, since the emulator is not a console for
> > the program that runs on it.
> 
> I mean that going forward, with that, it won't sound so strange for 
> native Windows console applications to output ansi escape sequences
> instead of using the console APIs to control cursor positioning, etc.

Perhaps in 5 or 10 years, when previous Windows versions are no longer
important.  But not until then, IMO.  (My main development machine
still runs XPSP3, FWIW.)

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

* Re: [PATCH v2 24/25] Add new command to create extra console/mi UI channels
  2016-05-26 16:36                 ` Eli Zaretskii
@ 2016-05-26 16:41                   ` Pedro Alves
  0 siblings, 0 replies; 58+ messages in thread
From: Pedro Alves @ 2016-05-26 16:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 05/26/2016 05:36 PM, Eli Zaretskii wrote:
>> Cc: gdb-patches@sourceware.org

>> I mean that going forward, with that, it won't sound so strange for 
>> native Windows console applications to output ansi escape sequences
>> instead of using the console APIs to control cursor positioning, etc.
> 
> Perhaps in 5 or 10 years, when previous Windows versions are no longer
> important.  But not until then, IMO.  (My main development machine
> still runs XPSP3, FWIW.)

Yeah, agreed.  I don't see it as the default any time soon, but rather 
an option that once sounded foreign/alien in the Windows world,
and will now will start sounding normal.

Thanks,
Pedro Alves

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

end of thread, other threads:[~2016-05-26 16:41 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-21 15:21 [PATCH v2 00/25] Towards great frontend GDB consoles Pedro Alves
2016-03-21 15:21 ` [PATCH v2 12/25] Make command line editing (use of readline) be per UI Pedro Alves
2016-03-21 15:21 ` [PATCH v2 22/25] Make main_ui be heap allocated Pedro Alves
2016-03-22 10:14   ` Yao Qi
2016-05-06 11:50     ` Pedro Alves
2016-03-21 15:21 ` [PATCH v2 02/25] Make gdb_stdout&co be per UI Pedro Alves
2016-03-21 15:21 ` [PATCH v2 03/25] Make the interpreters " Pedro Alves
2016-03-21 15:21 ` [PATCH v2 01/25] Introduce "struct ui" Pedro Alves
2016-03-21 15:22 ` [PATCH v2 13/25] Always process target events in the main UI Pedro Alves
2016-03-22 10:26   ` Yao Qi
2016-05-06 11:53     ` Pedro Alves
2016-03-21 15:22 ` [PATCH v2 18/25] Replace the sync_execution global with a new enum prompt_state tristate Pedro Alves
2016-03-21 15:22 ` [PATCH v2 24/25] Add new command to create extra console/mi UI channels Pedro Alves
2016-03-21 16:31   ` Eli Zaretskii
2016-03-21 16:51     ` Pedro Alves
2016-03-21 17:12       ` Eli Zaretskii
2016-03-21 17:57         ` Pedro Alves
2016-05-26 11:43           ` Pedro Alves
2016-05-26 15:46             ` Eli Zaretskii
2016-05-26 16:03               ` Pedro Alves
2016-05-26 16:36                 ` Eli Zaretskii
2016-05-26 16:41                   ` Pedro Alves
2016-03-21 15:26 ` [PATCH v2 08/25] Make input_fd be per UI Pedro Alves
2016-03-22  9:46   ` Yao Qi
2016-05-06 11:53     ` Pedro Alves
2016-03-21 15:26 ` [PATCH v2 10/25] Delete def_uiout Pedro Alves
2016-03-21 15:27 ` [PATCH v2 15/25] Introduce display_mi_prompt Pedro Alves
2016-03-21 15:27 ` [PATCH v2 21/25] Only send sync execution command output to the UI that ran the command Pedro Alves
2016-03-21 15:27 ` [PATCH v2 09/25] Make outstream be per UI Pedro Alves
2016-03-21 15:27 ` [PATCH v2 23/25] Handle UI terminal closed Pedro Alves
2016-03-21 15:29 ` [PATCH v2 11/25] Make current_ui_out be per UI Pedro Alves
2016-03-21 15:29 ` [PATCH v2 04/25] Introduce interpreter factories Pedro Alves
2016-03-22  8:55   ` Yao Qi
2016-05-06 11:49     ` Pedro Alves
2016-03-21 15:29 ` [PATCH v2 17/25] Make gdb_in_secondary_prompt_p() be per UI Pedro Alves
2016-03-21 15:29 ` [PATCH v2 05/25] Make the intepreters output to all UIs Pedro Alves
2016-03-22  9:33   ` Yao Qi
2016-05-06 12:19     ` Pedro Alves
2016-03-21 15:29 ` [PATCH v2 16/25] Simplify starting the command event loop Pedro Alves
2016-03-21 15:30 ` [PATCH v2 19/25] New function should_print_stop_to_console Pedro Alves
2016-03-21 15:30 ` [PATCH v2 07/25] Make instream and serial_stdin be per UI Pedro Alves
2016-03-21 15:30 ` [PATCH v2 06/25] Always run async signal handlers in the main UI Pedro Alves
2016-03-21 15:30 ` [PATCH v2 20/25] Push thread->control.command_interp to the struct thread_fsm Pedro Alves
2016-03-21 15:30 ` [PATCH v2 25/25] Add command to list UIs Pedro Alves
2016-03-22 10:36   ` Yao Qi
2016-05-06 11:49     ` Pedro Alves
2016-03-21 15:39 ` [PATCH v2 14/25] Make target_terminal_inferior/ours almost nops on non-main UIs Pedro Alves
2016-03-21 16:34 ` [PATCH v2 00/25] Towards great frontend GDB consoles Eli Zaretskii
2016-03-21 17:02   ` Pedro Alves
2016-03-21 17:17     ` Eli Zaretskii
2016-03-21 17:43     ` Marc Khouzam
2016-03-21 18:35 ` Marc Khouzam
2016-03-21 18:51   ` Pedro Alves
2016-03-21 19:06     ` Marc Khouzam
2016-03-21 19:12       ` Pedro Alves
2016-05-06 12:58     ` Pedro Alves
2016-03-22 10:41 ` Yao Qi
2016-05-06 11:58   ` 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).