public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Some struct ui / struct interps cleanup
@ 2023-04-28 18:27 Simon Marchi
  2023-04-28 18:27 ` [PATCH 1/3] gdb: move struct ui and related things to ui.{c,h} Simon Marchi
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Simon Marchi @ 2023-04-28 18:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

I want to make some changes in this area, here are some small cleanups I
have identified that I thought could go in first.

Simon Marchi (3):
  gdb: move struct ui and related things to ui.{c,h}
  gdb: store interps in an intrusive_list
  gdb: remove ui_interp_info

 gdb/Makefile.in       |   2 +
 gdb/annotate.c        |   3 +-
 gdb/async-event.c     |   1 +
 gdb/breakpoint.c      |   1 +
 gdb/bt-utils.c        |   2 +-
 gdb/cli-out.c         |   2 +-
 gdb/cli/cli-cmds.c    |   1 +
 gdb/cli/cli-interp.c  |   1 +
 gdb/cli/cli-script.c  |   1 +
 gdb/compile/compile.c |   2 +-
 gdb/event-top.c       |  78 +------------
 gdb/exceptions.c      |   2 +-
 gdb/fork-child.c      |   2 +-
 gdb/guile/guile.c     |   1 +
 gdb/guile/scm-ports.c |   2 +-
 gdb/inf-loop.c        |   1 +
 gdb/infcall.c         |   1 +
 gdb/infcmd.c          |   2 +-
 gdb/infrun.c          |   1 +
 gdb/interps.c         | 105 ++++--------------
 gdb/interps.h         |   8 +-
 gdb/main.c            |   1 +
 gdb/mi/mi-interp.c    |   2 +-
 gdb/mi/mi-main.c      |   1 +
 gdb/python/py-dap.c   |   2 +-
 gdb/python/python.c   |   1 +
 gdb/target.c          |   2 +-
 gdb/top.c             | 149 +------------------------
 gdb/top.h             | 200 +--------------------------------
 gdb/tui/tui-interp.c  |   2 +-
 gdb/tui/tui-io.c      |   1 +
 gdb/tui/tui.c         |   1 +
 gdb/ui.c              | 251 ++++++++++++++++++++++++++++++++++++++++++
 gdb/ui.h              | 227 ++++++++++++++++++++++++++++++++++++++
 gdb/utils.c           |   1 +
 35 files changed, 547 insertions(+), 513 deletions(-)
 create mode 100644 gdb/ui.c
 create mode 100644 gdb/ui.h

-- 
2.40.1


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

* [PATCH 1/3] gdb: move struct ui and related things to ui.{c,h}
  2023-04-28 18:27 [PATCH 0/3] Some struct ui / struct interps cleanup Simon Marchi
@ 2023-04-28 18:27 ` Simon Marchi
  2023-04-28 18:27 ` [PATCH 2/3] gdb: store interps in an intrusive_list Simon Marchi
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Simon Marchi @ 2023-04-28 18:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

I'd like to move some things so they become methods on struct ui.  But
first, I think that struct ui and the related things are big enough to
deserve their own file, instead of being scattered through top.{c,h} and
event-top.c.

Change-Id: I15594269ace61fd76ef80a7b58f51ff3ab6979bc
---
 gdb/Makefile.in       |   2 +
 gdb/annotate.c        |   3 +-
 gdb/async-event.c     |   1 +
 gdb/breakpoint.c      |   1 +
 gdb/bt-utils.c        |   2 +-
 gdb/cli-out.c         |   2 +-
 gdb/cli/cli-cmds.c    |   1 +
 gdb/cli/cli-interp.c  |   1 +
 gdb/cli/cli-script.c  |   1 +
 gdb/compile/compile.c |   2 +-
 gdb/event-top.c       |  78 +------------
 gdb/exceptions.c      |   2 +-
 gdb/fork-child.c      |   2 +-
 gdb/guile/guile.c     |   1 +
 gdb/guile/scm-ports.c |   2 +-
 gdb/inf-loop.c        |   1 +
 gdb/infcall.c         |   1 +
 gdb/infcmd.c          |   2 +-
 gdb/infrun.c          |   1 +
 gdb/interps.c         |   2 +-
 gdb/main.c            |   1 +
 gdb/mi/mi-interp.c    |   2 +-
 gdb/mi/mi-main.c      |   1 +
 gdb/python/py-dap.c   |   2 +-
 gdb/python/python.c   |   1 +
 gdb/target.c          |   2 +-
 gdb/top.c             | 149 +------------------------
 gdb/top.h             | 200 +--------------------------------
 gdb/tui/tui-interp.c  |   2 +-
 gdb/tui/tui-io.c      |   1 +
 gdb/tui/tui.c         |   1 +
 gdb/ui.c              | 251 ++++++++++++++++++++++++++++++++++++++++++
 gdb/ui.h              | 218 ++++++++++++++++++++++++++++++++++++
 gdb/utils.c           |   1 +
 34 files changed, 512 insertions(+), 428 deletions(-)
 create mode 100644 gdb/ui.c
 create mode 100644 gdb/ui.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 404975418804..6af65357243a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1209,6 +1209,7 @@ COMMON_SFILES = \
 	target-float.c \
 	type-stack.c \
 	typeprint.c \
+	ui.c \
 	ui-file.c \
 	ui-out.c \
 	ui-style.c \
@@ -1496,6 +1497,7 @@ HFILES_NO_SRCDIR = \
 	tramp-frame.h \
 	type-stack.h \
 	typeprint.h \
+	ui.h \
 	ui-file.h \
 	ui-out.h \
 	ui-style.h \
diff --git a/gdb/annotate.c b/gdb/annotate.c
index 60fe6ccd5c27..d403a47ba2f2 100644
--- a/gdb/annotate.c
+++ b/gdb/annotate.c
@@ -25,11 +25,10 @@
 #include "observable.h"
 #include "inferior.h"
 #include "infrun.h"
-#include "top.h"
 #include "source.h"
 #include "objfiles.h"
 #include "source-cache.h"
-\f
+#include "ui.h"
 
 /* Prototypes for local functions.  */
 
diff --git a/gdb/async-event.c b/gdb/async-event.c
index a190e77f3294..a094f314aa3f 100644
--- a/gdb/async-event.c
+++ b/gdb/async-event.c
@@ -21,6 +21,7 @@
 
 #include "ser-event.h"
 #include "top.h"
+#include "ui.h"
 
 /* PROC is a function to be invoked when the READY flag is set.  This
    happens when there has been a signal and the corresponding signal
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 46287da5f87c..7466854d5106 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -53,6 +53,7 @@
 #include "memattr.h"
 #include "ada-lang.h"
 #include "top.h"
+#include "ui.h"
 #include "valprint.h"
 #include "jit.h"
 #include "parser-defs.h"
diff --git a/gdb/bt-utils.c b/gdb/bt-utils.c
index 68c3f0816758..894403513324 100644
--- a/gdb/bt-utils.c
+++ b/gdb/bt-utils.c
@@ -19,7 +19,7 @@
 #include "bt-utils.h"
 #include "command.h"
 #include "gdbcmd.h"
-#include "top.h"
+#include "ui.h"
 #include "cli/cli-decode.h"
 
 /* See bt-utils.h.  */
diff --git a/gdb/cli-out.c b/gdb/cli-out.c
index fdfd0f7f0cf4..4c598883d4ba 100644
--- a/gdb/cli-out.c
+++ b/gdb/cli-out.c
@@ -26,7 +26,7 @@
 #include "completer.h"
 #include "readline/readline.h"
 #include "cli/cli-style.h"
-#include "top.h"
+#include "ui.h"
 
 /* These are the CLI output functions */
 
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 3b1c6a9f4bd6..d466cc6c34d7 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -45,6 +45,7 @@
 #include "interps.h"
 
 #include "top.h"
+#include "ui.h"
 #include "cli/cli-decode.h"
 #include "cli/cli-script.h"
 #include "cli/cli-setshow.h"
diff --git a/gdb/cli/cli-interp.c b/gdb/cli/cli-interp.c
index 5a515c603c6e..84fe34a10148 100644
--- a/gdb/cli/cli-interp.c
+++ b/gdb/cli/cli-interp.c
@@ -24,6 +24,7 @@
 #include "ui-out.h"
 #include "cli-out.h"
 #include "top.h"		/* for "execute_command" */
+#include "ui.h"
 #include "infrun.h"
 #include "observable.h"
 #include "gdbthread.h"
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index 294a5f18fe6c..2798faf82ec5 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -23,6 +23,7 @@
 
 #include "ui-out.h"
 #include "top.h"
+#include "ui.h"
 #include "breakpoint.h"
 #include "tracepoint.h"
 #include "cli/cli-cmds.h"
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index c07686c32e0b..a93c94046600 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 "top.h"
+#include "ui.h"
 #include "ui-out.h"
 #include "command.h"
 #include "cli/cli-script.h"
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 53ddd515be73..193ea5363ffc 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -21,6 +21,7 @@
 
 #include "defs.h"
 #include "top.h"
+#include "ui.h"
 #include "inferior.h"
 #include "infrun.h"
 #include "target.h"
@@ -480,12 +481,6 @@ top_level_prompt (void)
   return prompt;
 }
 
-/* See top.h.  */
-
-struct ui *main_ui;
-struct ui *current_ui;
-struct ui *ui_list;
-
 /* Get a reference to the current UI's line buffer.  This is used to
    construct a whole line of input from partial input.  */
 
@@ -495,77 +490,6 @@ get_command_line_buffer (void)
   return current_ui->line_buffer;
 }
 
-/* When there is an event ready on the stdin file descriptor, instead
-   of calling readline directly throught the callback function, or
-   instead of calling gdb_readline_no_editing_callback, give gdb a
-   chance to detect errors and do something.  */
-
-static void
-stdin_event_handler (int error, gdb_client_data client_data)
-{
-  struct ui *ui = (struct ui *) client_data;
-
-  if (error)
-    {
-      /* Switch to the main UI, so diagnostics always go there.  */
-      current_ui = main_ui;
-
-      ui->unregister_file_handler ();
-      if (main_ui == ui)
-	{
-	  /* If stdin died, we may as well kill gdb.  */
-	  gdb_printf (gdb_stderr, _("error detected on stdin\n"));
-	  quit_command ((char *) 0, 0);
-	}
-      else
-	{
-	  /* Simply delete the UI.  */
-	  delete ui;
-	}
-    }
-  else
-    {
-      /* Switch to the UI whose input descriptor woke up the event
-	 loop.  */
-      current_ui = ui;
-
-      /* This makes sure a ^C immediately followed by further input is
-	 always processed in that order.  E.g,. with input like
-	 "^Cprint 1\n", the SIGINT handler runs, marks the async
-	 signal handler, and then select/poll may return with stdin
-	 ready, instead of -1/EINTR.  The
-	 gdb.base/double-prompt-target-event-error.exp test exercises
-	 this.  */
-      QUIT;
-
-      do
-	{
-	  call_stdin_event_handler_again_p = 0;
-	  ui->call_readline (client_data);
-	}
-      while (call_stdin_event_handler_again_p != 0);
-    }
-}
-
-/* See top.h.  */
-
-void
-ui::register_file_handler ()
-{
-  if (input_fd != -1)
-    add_file_handler (input_fd, stdin_event_handler, this,
-		      string_printf ("ui-%d", num), true);
-}
-
-/* See top.h.  */
-
-void
-ui::unregister_file_handler ()
-{
-  if (input_fd != -1)
-    delete_file_handler (input_fd);
-}
-
 /* Re-enable stdin after the end of an execution command in
    synchronous mode, or after an error from the target, and we aborted
    the exec operation.  */
diff --git a/gdb/exceptions.c b/gdb/exceptions.c
index 8b7858578a90..2ba5a9c9fad1 100644
--- a/gdb/exceptions.c
+++ b/gdb/exceptions.c
@@ -26,7 +26,7 @@
 #include "ui-out.h"
 #include "serial.h"
 #include "gdbthread.h"
-#include "top.h"
+#include "ui.h"
 #include "gdbsupport/gdb_optional.h"
 
 static void
diff --git a/gdb/fork-child.c b/gdb/fork-child.c
index d210427f4b01..9e6f80a7953e 100644
--- a/gdb/fork-child.c
+++ b/gdb/fork-child.c
@@ -24,7 +24,7 @@
 #include "gdbcmd.h"
 #include "terminal.h"
 #include "gdbthread.h"
-#include "top.h"
+#include "ui.h"
 #include "gdbsupport/job-control.h"
 #include "gdbsupport/filestuff.h"
 #include "nat/fork-inferior.h"
diff --git a/gdb/guile/guile.c b/gdb/guile/guile.c
index 887b7fa5dc8f..b45081fe1cc1 100644
--- a/gdb/guile/guile.c
+++ b/gdb/guile/guile.c
@@ -28,6 +28,7 @@
 #include "command.h"
 #include "gdbcmd.h"
 #include "top.h"
+#include "ui.h"
 #include "extension-priv.h"
 #include "utils.h"
 #include "gdbsupport/version.h"
diff --git a/gdb/guile/scm-ports.c b/gdb/guile/scm-ports.c
index 48b607592344..a27ea8b3c80b 100644
--- a/gdb/guile/scm-ports.c
+++ b/gdb/guile/scm-ports.c
@@ -23,7 +23,7 @@
 
 #include "defs.h"
 #include "gdbsupport/gdb_select.h"
-#include "top.h"
+#include "ui.h"
 #include "target.h"
 #include "guile-internal.h"
 #include "gdbsupport/gdb_optional.h"
diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c
index b9f25008247c..8e7bcb67b3e6 100644
--- a/gdb/inf-loop.c
+++ b/gdb/inf-loop.c
@@ -28,6 +28,7 @@
 #include "gdbthread.h"
 #include "interps.h"
 #include "top.h"
+#include "ui.h"
 #include "observable.h"
 
 /* General function to handle events in the inferior.  */
diff --git a/gdb/infcall.c b/gdb/infcall.c
index e6cc6ed1a212..233ef5f29e9f 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -38,6 +38,7 @@
 #include "event-top.h"
 #include "observable.h"
 #include "top.h"
+#include "ui.h"
 #include "interps.h"
 #include "thread-fsm.h"
 #include <algorithm>
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 103899432f76..80107c946cc6 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -49,7 +49,7 @@
 #include "inf-loop.h"
 #include "linespec.h"
 #include "thread-fsm.h"
-#include "top.h"
+#include "ui.h"
 #include "interps.h"
 #include "skip.h"
 #include "gdbsupport/gdb_optional.h"
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2f1c6cd694be..efe2c00c489a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -34,6 +34,7 @@
 #include "annotate.h"
 #include "symfile.h"
 #include "top.h"
+#include "ui.h"
 #include "inf-loop.h"
 #include "regcache.h"
 #include "value.h"
diff --git a/gdb/interps.c b/gdb/interps.c
index ee451f27a639..a066c4acfedf 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -36,7 +36,7 @@
 #include "event-top.h"
 #include "interps.h"
 #include "completer.h"
-#include "top.h"		/* For command_loop.  */
+#include "ui.h"
 #include "main.h"
 #include "gdbsupport/buildargv.h"
 #include "gdbsupport/scope-exit.h"
diff --git a/gdb/main.c b/gdb/main.c
index 0bf6f98a797b..ac7cf8e3b580 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -19,6 +19,7 @@
 
 #include "defs.h"
 #include "top.h"
+#include "ui.h"
 #include "target.h"
 #include "inferior.h"
 #include "symfile.h"
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index ce78b0c2b58a..ad33a21374ab 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -27,7 +27,7 @@
 #include "inferior.h"
 #include "infrun.h"
 #include "ui-out.h"
-#include "top.h"
+#include "ui.h"
 #include "mi-main.h"
 #include "mi-cmds.h"
 #include "mi-out.h"
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 0013e5dfafdb..ee4ded0368ef 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -25,6 +25,7 @@
 #include "inferior.h"
 #include "infrun.h"
 #include "top.h"
+#include "ui.h"
 #include "gdbthread.h"
 #include "mi-cmds.h"
 #include "mi-parse.h"
diff --git a/gdb/python/py-dap.c b/gdb/python/py-dap.c
index 32f927214d75..52188406982b 100644
--- a/gdb/python/py-dap.c
+++ b/gdb/python/py-dap.c
@@ -21,7 +21,7 @@
 #include "python-internal.h"
 #include "interps.h"
 #include "cli-out.h"
-#include "top.h"
+#include "ui.h"
 
 class dap_interp final : public interp
 {
diff --git a/gdb/python/python.c b/gdb/python/python.c
index ea51766ec3e1..168a0009f1b2 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -64,6 +64,7 @@ static const char *gdbpy_should_print_stack = python_excp_message;
 #include "cli/cli-decode.h"
 #include "charset.h"
 #include "top.h"
+#include "ui.h"
 #include "python-internal.h"
 #include "linespec.h"
 #include "source.h"
diff --git a/gdb/target.c b/gdb/target.c
index 0cebecfafc37..80d2c80d4bfb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -44,7 +44,7 @@
 #include "gdbsupport/agent.h"
 #include "auxv.h"
 #include "target-debug.h"
-#include "top.h"
+#include "ui.h"
 #include "event-top.h"
 #include <algorithm>
 #include "gdbsupport/byte-vector.h"
diff --git a/gdb/top.c b/gdb/top.c
index 81f74f72f610..0b819091d114 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -39,6 +39,7 @@
 #include "annotate.h"
 #include "completer.h"
 #include "top.h"
+#include "ui.h"
 #include "gdbsupport/version.h"
 #include "serial.h"
 #include "main.h"
@@ -253,13 +254,9 @@ void (*deprecated_call_command_hook) (struct cmd_list_element * c,
 
 void (*deprecated_context_hook) (int id);
 
-/* The highest UI number ever assigned.  */
-static int highest_ui_num;
-
-/* Unbuffer STREAM.  This is a wrapper around setbuf(STREAM, nullptr)
-   which applies some special rules for MS-Windows hosts.  */
+/* See top.h.  */
 
-static void
+void
 unbuffer_stream (FILE *stream)
 {
   /* Unbuffer the input stream so that in gdb_readline_no_editing_callback,
@@ -291,118 +288,6 @@ unbuffer_stream (FILE *stream)
 #endif
 }
 
-/* See top.h.  */
-
-ui::ui (FILE *instream_, FILE *outstream_, FILE *errstream_)
-  : num (++highest_ui_num),
-    stdin_stream (instream_),
-    instream (instream_),
-    outstream (outstream_),
-    errstream (errstream_),
-    input_fd (fileno (instream)),
-    m_input_interactive_p (ISATTY (instream)),
-    m_gdb_stdout (new pager_file (new stdio_file (outstream))),
-    m_gdb_stdin (new stdio_file (instream)),
-    m_gdb_stderr (new stderr_file (errstream)),
-    m_gdb_stdlog (new timestamped_file (m_gdb_stderr))
-{
-  unbuffer_stream (instream_);
-
-  if (ui_list == NULL)
-    ui_list = this;
-  else
-    {
-      struct ui *last;
-
-      for (last = ui_list; last->next != NULL; last = last->next)
-	;
-      last->next = this;
-    }
-}
-
-ui::~ui ()
-{
-  struct ui *ui, *uiprev;
-
-  uiprev = NULL;
-
-  for (ui = ui_list; ui != NULL; uiprev = ui, ui = ui->next)
-    if (ui == this)
-      break;
-
-  gdb_assert (ui != NULL);
-
-  if (uiprev != NULL)
-    uiprev->next = next;
-  else
-    ui_list = next;
-
-  delete m_gdb_stdin;
-  delete m_gdb_stdout;
-  delete m_gdb_stderr;
-}
-
-/* Open file named NAME for read/write, making sure not to make it the
-   controlling terminal.  */
-
-static gdb_file_up
-open_terminal_stream (const char *name)
-{
-  scoped_fd fd = gdb_open_cloexec (name, O_RDWR | O_NOCTTY, 0);
-  if (fd.get () < 0)
-    perror_with_name  (_("opening terminal failed"));
-
-  return fd.to_file ("w+");
-}
-
-/* Implementation of the "new-ui" command.  */
-
-static void
-new_ui_command (const char *args, int from_tty)
-{
-  int argc;
-  const char *interpreter_name;
-  const char *tty_name;
-
-  dont_repeat ();
-
-  gdb_argv argv (args);
-  argc = argv.count ();
-
-  if (argc < 2)
-    error (_("Usage: new-ui INTERPRETER TTY"));
-
-  interpreter_name = argv[0];
-  tty_name = argv[1];
-
-  {
-    scoped_restore save_ui = make_scoped_restore (&current_ui);
-
-    /* Open specified terminal.  Note: we used to open it three times,
-       once for each of stdin/stdout/stderr, but that does not work
-       with Windows named pipes.  */
-    gdb_file_up stream = open_terminal_stream (tty_name);
-
-    std::unique_ptr<ui> ui
-      (new struct ui (stream.get (), stream.get (), stream.get ()));
-
-    ui->async = 1;
-
-    current_ui = ui.get ();
-
-    set_top_level_interpreter (interpreter_name);
-
-    interp_pre_command_loop (top_level_interpreter ());
-
-    /* Make sure the file is not closed.  */
-    stream.release ();
-
-    ui.release ();
-  }
-
-  gdb_printf ("New UI allocated\n");
-}
-
 /* Handler for SIGHUP.  */
 
 #ifdef SIGHUP
@@ -1917,8 +1802,9 @@ quit_force (int *exit_arg, int from_tty)
   exit (exit_code);
 }
 
-/* The value of the "interactive-mode" setting.  */
-static enum auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO;
+/* See top.h.  */
+
+auto_boolean interactive_mode = AUTO_BOOLEAN_AUTO;
 
 /* Implement the "show interactive-mode" option.  */
 
@@ -1935,20 +1821,6 @@ show_interactive_mode (struct ui_file *file, int from_tty,
     gdb_printf (file, "Debugger's interactive mode is %s.\n", value);
 }
 
-/* Returns whether GDB is running on an interactive terminal.  */
-
-bool
-ui::input_interactive_p () const
-{
-  if (batch_flag)
-    return false;
-
-  if (interactive_mode != AUTO_BOOLEAN_AUTO)
-    return interactive_mode == AUTO_BOOLEAN_TRUE;
-
-  return m_input_interactive_p;
-}
-\f
 static void
 dont_repeat_command (const char *ignored, int from_tty)
 {
@@ -2241,8 +2113,6 @@ show_startup_quiet (struct ui_file *file, int from_tty,
 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);
@@ -2395,13 +2265,6 @@ affect future GDB sessions."),
 			       show_startup_quiet,
 			       &setlist, &showlist);
 
-  c = add_cmd ("new-ui", class_support, new_ui_command, _("\
-Create a new UI.\n\
-Usage: new-ui INTERPRETER TTY\n\
-The first argument is the name of the interpreter to run.\n\
-The second argument is the terminal the UI runs on."), &cmdlist);
-  set_cmd_completer (c, interpreter_completer);
-
   struct internalvar *major_version_var = create_internalvar ("_gdb_major");
   struct internalvar *minor_version_var = create_internalvar ("_gdb_minor");
   int vmajor = 0, vminor = 0, vrevision = 0;
diff --git a/gdb/top.h b/gdb/top.h
index 5c1ccfee736f..47e16ca104ea 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -24,203 +24,10 @@
 #include "gdbsupport/next-iterator.h"
 #include "value.h"
 
-/* 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
-   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
-{
-  /* Create a new UI.  */
-  ui (FILE *instream, FILE *outstream, FILE *errstream);
-  ~ui ();
-
-  DISABLE_COPY_AND_ASSIGN (ui);
-
-  /* Pointer to next in singly-linked list.  */
-  struct ui *next = nullptr;
-
-  /* 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.  */
-  std::string 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) = nullptr;
-
-  /* The function to invoke when a complete line of input is ready for
-     processing.  */
-  void (*input_handler) (gdb::unique_xmalloc_ptr<char> &&) = nullptr;
-
-  /* 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 = 0;
-
-  /* Each UI has its own independent set of interpreters.  */
-  struct ui_interp_info *interp_info = nullptr;
-
-  /* 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 = 0;
-
-  /* The number of nested readline secondary prompts that are
-     currently active.  */
-  int secondary_prompt_depth = 0;
-
-  /* The UI's stdin.  Set to stdin for the main UI.  */
-  FILE *stdin_stream;
-
-  /* stdio stream that command input is being read from.  Set to stdin
-     normally.  Set by source_command to the file we are sourcing.
-     Set to NULL if we are executing a user-defined command or
-     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.  This can be set to -1 to prevent this
-     registration.  */
-  int input_fd;
-
-  /* Whether ISATTY returns true on input_fd.  Cached here because
-     quit_force needs to know this _after_ input_fd might be
-     closed.  */
-  bool m_input_interactive_p;
-
-  /* See enum prompt_state's description.  */
-  enum prompt_state prompt_state = PROMPT_NEEDED;
-
-  /* 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.  */
-  struct ui_file *m_gdb_stdlog;
-
-  /* The current ui_out.  */
-  struct ui_out *m_current_uiout = nullptr;
-
-  /* Register the UI's input file descriptor in the event loop.  */
-  void register_file_handler ();
-
-  /* Unregister the UI's input file descriptor from the event loop.  */
-  void unregister_file_handler ();
-
-  /* Return true if this UI's input fd is a tty.  */
-  bool input_interactive_p () const;
-};
-
-/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
-   It always exists and is created automatically when GDB starts
-   up.  */
-extern struct ui *main_ui;
-
-/* The current UI.  */
-extern struct ui *current_ui;
-
-/* The list of all UIs.  */
-extern struct ui *ui_list;
-
-/* State for SWITCH_THRU_ALL_UIS.  */
-class switch_thru_all_uis
-{
-public:
-
-  switch_thru_all_uis () : m_iter (ui_list), m_save_ui (&current_ui)
-  {
-    current_ui = ui_list;
-  }
-
-  DISABLE_COPY_AND_ASSIGN (switch_thru_all_uis);
-
-  /* If done iterating, return true; otherwise return false.  */
-  bool done () const
-  {
-    return m_iter == NULL;
-  }
-
-  /* Move to the next UI, setting current_ui if iteration is not yet
-     complete.  */
-  void next ()
-  {
-    m_iter = m_iter->next;
-    if (m_iter != NULL)
-      current_ui = m_iter;
-  }
-
- private:
-
-  /* Used to iterate through the UIs.  */
-  struct ui *m_iter;
-
-  /* Save and restore current_ui.  */
-  scoped_restore_tmpl<struct ui *> m_save_ui;
-};
-
-  /* Traverse through all UI, and switch the current UI to the one
-     being iterated.  */
-#define SWITCH_THRU_ALL_UIS()		\
-  for (switch_thru_all_uis stau_state; !stau_state.done (); stau_state.next ())
-
-using ui_range = next_range<ui>;
-
-/* An adapter that can be used to traverse over all UIs.  */
-static inline
-ui_range all_uis ()
-{
-  return ui_range (ui_list);
-}
-
 /* From top.c.  */
 extern bool confirm;
 extern int inhibit_gdbinit;
+extern auto_boolean interactive_mode;
 
 /* Print the GDB version banner to STREAM.  If INTERACTIVE is false,
    then information referring to commands (e.g., "show configuration")
@@ -297,4 +104,9 @@ extern const char *handle_line_of_input (std::string &cmd_line_buffer,
 
 extern bool check_quiet_mode ();
 
+/* Unbuffer STREAM.  This is a wrapper around setbuf(STREAM, nullptr)
+   which applies some special rules for MS-Windows hosts.  */
+
+extern void unbuffer_stream (FILE *stream);
+
 #endif
diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 812c62c64220..299cc4caea09 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -20,7 +20,7 @@
 #include "defs.h"
 #include "cli/cli-interp.h"
 #include "interps.h"
-#include "top.h"
+#include "ui.h"
 #include "event-top.h"
 #include "gdbsupport/event-loop.h"
 #include "ui-out.h"
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 7752701378e7..a1eadcd937d2 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -25,6 +25,7 @@
 #include "event-top.h"
 #include "command.h"
 #include "top.h"
+#include "ui.h"
 #include "tui/tui.h"
 #include "tui/tui-data.h"
 #include "tui/tui-io.h"
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index 3604194a760c..10cf811a41e9 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -41,6 +41,7 @@
 #include "source.h"
 #include "terminal.h"
 #include "top.h"
+#include "ui.h"
 
 #include <ctype.h>
 #include <signal.h>
diff --git a/gdb/ui.c b/gdb/ui.c
new file mode 100644
index 000000000000..5fe001262a83
--- /dev/null
+++ b/gdb/ui.c
@@ -0,0 +1,251 @@
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+#include "ui.h"
+
+#include "cli/cli-cmds.h"
+#include "event-top.h"
+#include "gdbsupport/buildargv.h"
+#include "gdbsupport/filestuff.h"
+#include "gdbsupport/gdb_file.h"
+#include "gdbsupport/scoped_fd.h"
+#include "interps.h"
+#include "pager.h"
+#include "main.h"
+#include "top.h"
+
+/* See top.h.  */
+
+struct ui *main_ui;
+struct ui *current_ui;
+struct ui *ui_list;
+
+/* The highest UI number ever assigned.  */
+
+static int highest_ui_num;
+
+/* See top.h.  */
+
+ui::ui (FILE *instream_, FILE *outstream_, FILE *errstream_)
+  : num (++highest_ui_num),
+    stdin_stream (instream_),
+    instream (instream_),
+    outstream (outstream_),
+    errstream (errstream_),
+    input_fd (fileno (instream)),
+    m_input_interactive_p (ISATTY (instream)),
+    m_gdb_stdout (new pager_file (new stdio_file (outstream))),
+    m_gdb_stdin (new stdio_file (instream)),
+    m_gdb_stderr (new stderr_file (errstream)),
+    m_gdb_stdlog (new timestamped_file (m_gdb_stderr))
+{
+  unbuffer_stream (instream_);
+
+  if (ui_list == NULL)
+    ui_list = this;
+  else
+    {
+      struct ui *last;
+
+      for (last = ui_list; last->next != NULL; last = last->next)
+	;
+      last->next = this;
+    }
+}
+
+ui::~ui ()
+{
+  struct ui *ui, *uiprev;
+
+  uiprev = NULL;
+
+  for (ui = ui_list; ui != NULL; uiprev = ui, ui = ui->next)
+    if (ui == this)
+      break;
+
+  gdb_assert (ui != NULL);
+
+  if (uiprev != NULL)
+    uiprev->next = next;
+  else
+    ui_list = next;
+
+  delete m_gdb_stdin;
+  delete m_gdb_stdout;
+  delete m_gdb_stderr;
+}
+
+
+/* Returns whether GDB is running on an interactive terminal.  */
+
+bool
+ui::input_interactive_p () const
+{
+  if (batch_flag)
+    return false;
+
+  if (interactive_mode != AUTO_BOOLEAN_AUTO)
+    return interactive_mode == AUTO_BOOLEAN_TRUE;
+
+  return m_input_interactive_p;
+}
+
+
+/* When there is an event ready on the stdin file descriptor, instead
+   of calling readline directly throught the callback function, or
+   instead of calling gdb_readline_no_editing_callback, give gdb a
+   chance to detect errors and do something.  */
+
+static void
+stdin_event_handler (int error, gdb_client_data client_data)
+{
+  struct ui *ui = (struct ui *) client_data;
+
+  if (error)
+    {
+      /* Switch to the main UI, so diagnostics always go there.  */
+      current_ui = main_ui;
+
+      ui->unregister_file_handler ();
+      if (main_ui == ui)
+	{
+	  /* If stdin died, we may as well kill gdb.  */
+	  gdb_printf (gdb_stderr, _("error detected on stdin\n"));
+	  quit_command ((char *) 0, 0);
+	}
+      else
+	{
+	  /* Simply delete the UI.  */
+	  delete ui;
+	}
+    }
+  else
+    {
+      /* Switch to the UI whose input descriptor woke up the event
+	 loop.  */
+      current_ui = ui;
+
+      /* This makes sure a ^C immediately followed by further input is
+	 always processed in that order.  E.g,. with input like
+	 "^Cprint 1\n", the SIGINT handler runs, marks the async
+	 signal handler, and then select/poll may return with stdin
+	 ready, instead of -1/EINTR.  The
+	 gdb.base/double-prompt-target-event-error.exp test exercises
+	 this.  */
+      QUIT;
+
+      do
+	{
+	  call_stdin_event_handler_again_p = 0;
+	  ui->call_readline (client_data);
+	}
+      while (call_stdin_event_handler_again_p != 0);
+    }
+}
+
+/* See top.h.  */
+
+void
+ui::register_file_handler ()
+{
+  if (input_fd != -1)
+    add_file_handler (input_fd, stdin_event_handler, this,
+		      string_printf ("ui-%d", num), true);
+}
+
+/* See top.h.  */
+
+void
+ui::unregister_file_handler ()
+{
+  if (input_fd != -1)
+    delete_file_handler (input_fd);
+}
+
+/* Open file named NAME for read/write, making sure not to make it the
+   controlling terminal.  */
+
+static gdb_file_up
+open_terminal_stream (const char *name)
+{
+  scoped_fd fd = gdb_open_cloexec (name, O_RDWR | O_NOCTTY, 0);
+  if (fd.get () < 0)
+    perror_with_name  (_("opening terminal failed"));
+
+  return fd.to_file ("w+");
+}
+
+/* Implementation of the "new-ui" command.  */
+
+static void
+new_ui_command (const char *args, int from_tty)
+{
+  int argc;
+  const char *interpreter_name;
+  const char *tty_name;
+
+  dont_repeat ();
+
+  gdb_argv argv (args);
+  argc = argv.count ();
+
+  if (argc < 2)
+    error (_("Usage: new-ui INTERPRETER TTY"));
+
+  interpreter_name = argv[0];
+  tty_name = argv[1];
+
+  {
+    scoped_restore save_ui = make_scoped_restore (&current_ui);
+
+    /* Open specified terminal.  Note: we used to open it three times,
+       once for each of stdin/stdout/stderr, but that does not work
+       with Windows named pipes.  */
+    gdb_file_up stream = open_terminal_stream (tty_name);
+
+    std::unique_ptr<ui> ui
+      (new struct ui (stream.get (), stream.get (), stream.get ()));
+
+    ui->async = 1;
+
+    current_ui = ui.get ();
+
+    set_top_level_interpreter (interpreter_name);
+
+    interp_pre_command_loop (top_level_interpreter ());
+
+    /* Make sure the file is not closed.  */
+    stream.release ();
+
+    ui.release ();
+  }
+
+  gdb_printf ("New UI allocated\n");
+}
+
+void _initialize_ui ();
+void
+_initialize_ui ()
+{
+  cmd_list_element *c = add_cmd ("new-ui", class_support, new_ui_command, _("\
+Create a new UI.\n\
+Usage: new-ui INTERPRETER TTY\n\
+The first argument is the name of the interpreter to run.\n\
+The second argument is the terminal the UI runs on."), &cmdlist);
+  set_cmd_completer (c, interpreter_completer);
+}
diff --git a/gdb/ui.h b/gdb/ui.h
new file mode 100644
index 000000000000..8da4b2d8eeed
--- /dev/null
+++ b/gdb/ui.h
@@ -0,0 +1,218 @@
+/* Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 UI_H
+#define UI_H
+
+#include "gdbsupport/event-loop.h"
+#include "gdbsupport/next-iterator.h"
+
+/* 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
+   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
+{
+  /* Create a new UI.  */
+  ui (FILE *instream, FILE *outstream, FILE *errstream);
+  ~ui ();
+
+  DISABLE_COPY_AND_ASSIGN (ui);
+
+  /* Pointer to next in singly-linked list.  */
+  struct ui *next = nullptr;
+
+  /* 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.  */
+  std::string 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) = nullptr;
+
+  /* The function to invoke when a complete line of input is ready for
+     processing.  */
+  void (*input_handler) (gdb::unique_xmalloc_ptr<char> &&) = nullptr;
+
+  /* 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 = 0;
+
+  /* Each UI has its own independent set of interpreters.  */
+  struct ui_interp_info *interp_info = nullptr;
+
+  /* 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 = 0;
+
+  /* The number of nested readline secondary prompts that are
+     currently active.  */
+  int secondary_prompt_depth = 0;
+
+  /* The UI's stdin.  Set to stdin for the main UI.  */
+  FILE *stdin_stream;
+
+  /* stdio stream that command input is being read from.  Set to stdin
+     normally.  Set by source_command to the file we are sourcing.
+     Set to NULL if we are executing a user-defined command or
+     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.  This can be set to -1 to prevent this
+     registration.  */
+  int input_fd;
+
+  /* Whether ISATTY returns true on input_fd.  Cached here because
+     quit_force needs to know this _after_ input_fd might be
+     closed.  */
+  bool m_input_interactive_p;
+
+  /* See enum prompt_state's description.  */
+  enum prompt_state prompt_state = PROMPT_NEEDED;
+
+  /* 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.  */
+  struct ui_file *m_gdb_stdlog;
+
+  /* The current ui_out.  */
+  struct ui_out *m_current_uiout = nullptr;
+
+  /* Register the UI's input file descriptor in the event loop.  */
+  void register_file_handler ();
+
+  /* Unregister the UI's input file descriptor from the event loop.  */
+  void unregister_file_handler ();
+
+  /* Return true if this UI's input fd is a tty.  */
+  bool input_interactive_p () const;
+};
+
+/* The main UI.  This is the UI that is bound to stdin/stdout/stderr.
+   It always exists and is created automatically when GDB starts
+   up.  */
+extern struct ui *main_ui;
+
+/* The current UI.  */
+extern struct ui *current_ui;
+
+/* The list of all UIs.  */
+extern struct ui *ui_list;
+
+/* State for SWITCH_THRU_ALL_UIS.  */
+class switch_thru_all_uis
+{
+public:
+
+  switch_thru_all_uis () : m_iter (ui_list), m_save_ui (&current_ui)
+  {
+    current_ui = ui_list;
+  }
+
+  DISABLE_COPY_AND_ASSIGN (switch_thru_all_uis);
+
+  /* If done iterating, return true; otherwise return false.  */
+  bool done () const
+  {
+    return m_iter == NULL;
+  }
+
+  /* Move to the next UI, setting current_ui if iteration is not yet
+     complete.  */
+  void next ()
+  {
+    m_iter = m_iter->next;
+    if (m_iter != NULL)
+      current_ui = m_iter;
+  }
+
+ private:
+
+  /* Used to iterate through the UIs.  */
+  struct ui *m_iter;
+
+  /* Save and restore current_ui.  */
+  scoped_restore_tmpl<struct ui *> m_save_ui;
+};
+
+  /* Traverse through all UI, and switch the current UI to the one
+     being iterated.  */
+#define SWITCH_THRU_ALL_UIS()		\
+  for (switch_thru_all_uis stau_state; !stau_state.done (); stau_state.next ())
+
+using ui_range = next_range<ui>;
+
+/* An adapter that can be used to traverse over all UIs.  */
+static inline
+ui_range all_uis ()
+{
+  return ui_range (ui_list);
+}
+
+#endif /* UI_H */
diff --git a/gdb/utils.c b/gdb/utils.c
index b5bb84ce85db..bf1475285988 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -52,6 +52,7 @@
 #include "gdbsupport/gdb_obstack.h"
 #include "gdbcore.h"
 #include "top.h"
+#include "ui.h"
 #include "main.h"
 #include "solist.h"
 
-- 
2.40.1


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

* [PATCH 2/3] gdb: store interps in an intrusive_list
  2023-04-28 18:27 [PATCH 0/3] Some struct ui / struct interps cleanup Simon Marchi
  2023-04-28 18:27 ` [PATCH 1/3] gdb: move struct ui and related things to ui.{c,h} Simon Marchi
@ 2023-04-28 18:27 ` Simon Marchi
  2023-04-28 18:27 ` [PATCH 3/3] gdb: remove ui_interp_info Simon Marchi
  2023-05-01 15:25 ` [PATCH 0/3] Some struct ui / struct interps cleanup Tom Tromey
  3 siblings, 0 replies; 6+ messages in thread
From: Simon Marchi @ 2023-04-28 18:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

Use intrusive_list, instead of hand-made linked list.

Change-Id: Idc857b40dfa3e3c35671045898331cca2c928097
---
 gdb/interps.c | 18 ++++++------------
 gdb/interps.h |  8 +++-----
 2 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/gdb/interps.c b/gdb/interps.c
index a066c4acfedf..54e1cb45db68 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -49,7 +49,7 @@ struct ui_interp_info
   DISABLE_COPY_AND_ASSIGN (ui_interp_info);
 
   /* Each top level has its own independent set of interpreters.  */
-  interp *interp_list = nullptr;
+  intrusive_list<interp> interp_list;
   interp *current_interpreter = nullptr;
   interp *top_level_interpreter = nullptr;
 
@@ -132,8 +132,7 @@ interp_add (struct ui *ui, struct interp *interp)
 
   gdb_assert (interp_lookup_existing (ui, interp->name ()) == NULL);
 
-  interp->next = ui_interp.interp_list;
-  ui_interp.interp_list = interp;
+  ui_interp.interp_list.push_back (*interp);
 }
 
 /* This sets the current interpreter to be INTERP.  If INTERP has not
@@ -204,17 +203,12 @@ static struct interp *
 interp_lookup_existing (struct ui *ui, const char *name)
 {
   ui_interp_info &ui_interp = get_interp_info (ui);
-  struct interp *interp;
 
-  for (interp = ui_interp.interp_list;
-       interp != NULL;
-       interp = interp->next)
-    {
-      if (strcmp (interp->name (), name) == 0)
-	return interp;
-    }
+  for (interp &interp : ui_interp.interp_list)
+    if (strcmp (interp.name (), name) == 0)
+      return &interp;
 
-  return NULL;
+  return nullptr;
 }
 
 /* See interps.h.  */
diff --git a/gdb/interps.h b/gdb/interps.h
index 29248093c671..da78a5d89fae 100644
--- a/gdb/interps.h
+++ b/gdb/interps.h
@@ -22,6 +22,8 @@
 #ifndef INTERPS_H
 #define INTERPS_H
 
+#include "gdbsupport/intrusive_list.h"
+
 struct ui_out;
 struct interp;
 struct ui;
@@ -40,7 +42,7 @@ extern void interp_factory_register (const char *name,
 
 extern void interp_exec (struct interp *interp, const char *command);
 
-class interp
+class interp : public intrusive_list_node<interp>
 {
 public:
   explicit interp (const char *name);
@@ -85,10 +87,6 @@ class interp
   const char *m_name;
 
 public:
-  /* Interpreters are stored in a linked list, this is the next
-     one...  */
-  interp *next = nullptr;
-
   /* Has the init method been run?  */
   bool inited = false;
 };
-- 
2.40.1


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

* [PATCH 3/3] gdb: remove ui_interp_info
  2023-04-28 18:27 [PATCH 0/3] Some struct ui / struct interps cleanup Simon Marchi
  2023-04-28 18:27 ` [PATCH 1/3] gdb: move struct ui and related things to ui.{c,h} Simon Marchi
  2023-04-28 18:27 ` [PATCH 2/3] gdb: store interps in an intrusive_list Simon Marchi
@ 2023-04-28 18:27 ` Simon Marchi
  2023-05-01 15:25 ` [PATCH 0/3] Some struct ui / struct interps cleanup Tom Tromey
  3 siblings, 0 replies; 6+ messages in thread
From: Simon Marchi @ 2023-04-28 18:27 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

I don't think that having struct ui_interp_info separated from struct ui
is very useful.  As of today, it looks like an unnecessary indirection
layer.  Move the contents of ui_interp_info directly into struct ui, and
update all users.

Change-Id: I817ba6e047dbcc4ba15b666af184b40bfed7e521
---
 gdb/interps.c | 91 +++++++++++----------------------------------------
 gdb/ui.h      | 11 ++++++-
 2 files changed, 30 insertions(+), 72 deletions(-)

diff --git a/gdb/interps.c b/gdb/interps.c
index 54e1cb45db68..e3f6ee685123 100644
--- a/gdb/interps.c
+++ b/gdb/interps.c
@@ -41,41 +41,6 @@
 #include "gdbsupport/buildargv.h"
 #include "gdbsupport/scope-exit.h"
 
-/* Each UI has its own independent set of interpreters.  */
-
-struct ui_interp_info
-{
-  ui_interp_info () = default;
-  DISABLE_COPY_AND_ASSIGN (ui_interp_info);
-
-  /* Each top level has its own independent set of interpreters.  */
-  intrusive_list<interp> interp_list;
-  interp *current_interpreter = nullptr;
-  interp *top_level_interpreter = nullptr;
-
-  /* The interpreter that is active while `interp_exec' is active, NULL
-     at all other times.  */
-  interp *command_interpreter = nullptr;
-};
-
-/* Get UI's ui_interp_info object.  */
-
-static ui_interp_info &
-get_interp_info (struct ui *ui)
-{
-  if (ui->interp_info == NULL)
-    ui->interp_info = new ui_interp_info;
-  return *ui->interp_info;
-}
-
-/* Get the current UI's ui_interp_info object.  */
-
-static ui_interp_info &
-get_current_interp_info (void)
-{
-  return get_interp_info (current_ui);
-}
-
 /* The magic initialization routine for this module.  */
 
 static struct interp *interp_lookup_existing (struct ui *ui,
@@ -128,11 +93,9 @@ interp_factory_register (const char *name, interp_factory_func func)
 static void
 interp_add (struct ui *ui, struct interp *interp)
 {
-  ui_interp_info &ui_interp = get_interp_info (ui);
-
   gdb_assert (interp_lookup_existing (ui, interp->name ()) == NULL);
 
-  ui_interp.interp_list.push_back (*interp);
+  ui->interp_list.push_back (*interp);
 }
 
 /* This sets the current interpreter to be INTERP.  If INTERP has not
@@ -149,13 +112,12 @@ interp_add (struct ui *ui, struct interp *interp)
 static void
 interp_set (struct interp *interp, bool top_level)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-  struct interp *old_interp = ui_interp.current_interpreter;
+  struct interp *old_interp = current_ui->current_interpreter;
 
   /* If we already have an interpreter, then trying to
      set top level interpreter is kinda pointless.  */
-  gdb_assert (!top_level || !ui_interp.current_interpreter);
-  gdb_assert (!top_level || !ui_interp.top_level_interpreter);
+  gdb_assert (!top_level || !current_ui->current_interpreter);
+  gdb_assert (!top_level || !current_ui->top_level_interpreter);
 
   if (old_interp != NULL)
     {
@@ -163,9 +125,9 @@ interp_set (struct interp *interp, bool top_level)
       old_interp->suspend ();
     }
 
-  ui_interp.current_interpreter = interp;
+  current_ui->current_interpreter = interp;
   if (top_level)
-    ui_interp.top_level_interpreter = interp;
+    current_ui->top_level_interpreter = interp;
 
   if (interpreter_p != interp->name ())
     interpreter_p = interp->name ();
@@ -202,9 +164,7 @@ interp_set (struct interp *interp, bool top_level)
 static struct interp *
 interp_lookup_existing (struct ui *ui, const char *name)
 {
-  ui_interp_info &ui_interp = get_interp_info (ui);
-
-  for (interp &interp : ui_interp.interp_list)
+  for (interp &interp : ui->interp_list)
     if (strcmp (interp.name (), name) == 0)
       return &interp;
 
@@ -253,8 +213,7 @@ void
 current_interp_set_logging (ui_file_up logfile, bool logging_redirect,
 			    bool debug_redirect)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-  struct interp *interp = ui_interp.current_interpreter;
+  struct interp *interp = current_ui->current_interpreter;
 
   interp->set_logging (std::move (logfile), logging_redirect, debug_redirect);
 }
@@ -263,12 +222,12 @@ current_interp_set_logging (ui_file_up logfile, bool logging_redirect,
 struct interp *
 scoped_restore_interp::set_interp (const char *name)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
   struct interp *interp = interp_lookup (current_ui, name);
-  struct interp *old_interp = ui_interp.current_interpreter;
+  struct interp *old_interp = current_ui->current_interpreter;
 
   if (interp)
-    ui_interp.current_interpreter = interp;
+    current_ui->current_interpreter = interp;
+
   return old_interp;
 }
 
@@ -276,8 +235,7 @@ scoped_restore_interp::set_interp (const char *name)
 int
 current_interp_named_p (const char *interp_name)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-  struct interp *interp = ui_interp.current_interpreter;
+  interp *interp = current_ui->current_interpreter;
 
   if (interp != NULL)
     return (strcmp (interp->name (), interp_name) == 0);
@@ -298,12 +256,10 @@ current_interp_named_p (const char *interp_name)
 struct interp *
 command_interp (void)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-
-  if (ui_interp.command_interpreter != NULL)
-    return ui_interp.command_interpreter;
+  if (current_ui->command_interpreter != nullptr)
+    return current_ui->command_interpreter;
   else
-    return ui_interp.current_interpreter;
+    return current_ui->current_interpreter;
 }
 
 /* See interps.h.  */
@@ -330,11 +286,9 @@ interp_supports_command_editing (struct interp *interp)
 void
 interp_exec (struct interp *interp, const char *command_str)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-
   /* See `command_interp' for why we do this.  */
   scoped_restore save_command_interp
-    = make_scoped_restore (&ui_interp.command_interpreter, interp);
+    = make_scoped_restore (&current_ui->command_interpreter, interp);
 
   interp->exec (command_str);
 }
@@ -359,8 +313,7 @@ clear_interpreter_hooks (void)
 static void
 interpreter_exec_cmd (const char *args, int from_tty)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-  struct interp *old_interp, *interp_to_use;
+  struct interp *interp_to_use;
   unsigned int nrules;
   unsigned int i;
 
@@ -381,7 +334,7 @@ interpreter_exec_cmd (const char *args, int from_tty)
   if (nrules < 2)
     error (_("Usage: interpreter-exec INTERPRETER COMMAND..."));
 
-  old_interp = ui_interp.current_interpreter;
+  interp *old_interp = current_ui->current_interpreter;
 
   interp_to_use = interp_lookup (current_ui, prules[0]);
   if (interp_to_use == NULL)
@@ -419,9 +372,7 @@ interpreter_completer (struct cmd_list_element *ignore,
 struct interp *
 top_level_interpreter (void)
 {
-  ui_interp_info &ui_interp = get_current_interp_info ();
-
-  return ui_interp.top_level_interpreter;
+  return current_ui->top_level_interpreter;
 }
 
 /* See interps.h.  */
@@ -429,9 +380,7 @@ top_level_interpreter (void)
 struct interp *
 current_interpreter (void)
 {
-  ui_interp_info &ui_interp = get_interp_info (current_ui);
-
-  return ui_interp.current_interpreter;
+  return current_ui->current_interpreter;
 }
 
 /* This just adds the "interpreter-exec" command.  */
diff --git a/gdb/ui.h b/gdb/ui.h
index 8da4b2d8eeed..ed75e041e5f2 100644
--- a/gdb/ui.h
+++ b/gdb/ui.h
@@ -19,8 +19,11 @@
 #define UI_H
 
 #include "gdbsupport/event-loop.h"
+#include "gdbsupport/intrusive_list.h"
 #include "gdbsupport/next-iterator.h"
 
+struct interp;
+
 /* Prompt state.  */
 
 enum prompt_state
@@ -84,7 +87,13 @@ struct ui
   int command_editing = 0;
 
   /* Each UI has its own independent set of interpreters.  */
-  struct ui_interp_info *interp_info = nullptr;
+  intrusive_list<interp> interp_list;
+  interp *current_interpreter = nullptr;
+  interp *top_level_interpreter = nullptr;
+
+  /* The interpreter that is active while `interp_exec' is active, NULL
+     at all other times.  */
+  interp *command_interpreter = nullptr;
 
   /* 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
-- 
2.40.1


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

* Re: [PATCH 0/3] Some struct ui / struct interps cleanup
  2023-04-28 18:27 [PATCH 0/3] Some struct ui / struct interps cleanup Simon Marchi
                   ` (2 preceding siblings ...)
  2023-04-28 18:27 ` [PATCH 3/3] gdb: remove ui_interp_info Simon Marchi
@ 2023-05-01 15:25 ` Tom Tromey
  2023-05-02  0:49   ` Simon Marchi
  3 siblings, 1 reply; 6+ messages in thread
From: Tom Tromey @ 2023-05-01 15:25 UTC (permalink / raw)
  To: Simon Marchi via Gdb-patches; +Cc: Simon Marchi

>>>>> "Simon" == Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:

Simon> I want to make some changes in this area, here are some small cleanups I
Simon> have identified that I thought could go in first.

These all seem fine to me.  Thanks for doing this.

Reviewed-By: Tom Tromey <tom@tromey.com>

Tom

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

* Re: [PATCH 0/3] Some struct ui / struct interps cleanup
  2023-05-01 15:25 ` [PATCH 0/3] Some struct ui / struct interps cleanup Tom Tromey
@ 2023-05-02  0:49   ` Simon Marchi
  0 siblings, 0 replies; 6+ messages in thread
From: Simon Marchi @ 2023-05-02  0:49 UTC (permalink / raw)
  To: Tom Tromey, Simon Marchi via Gdb-patches; +Cc: Simon Marchi



On 5/1/23 11:25, Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:
> 
> Simon> I want to make some changes in this area, here are some small cleanups I
> Simon> have identified that I thought could go in first.
> 
> These all seem fine to me.  Thanks for doing this.
> 
> Reviewed-By: Tom Tromey <tom@tromey.com>
> 
> Tom

Thanks, I pushed it.

Simon

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

end of thread, other threads:[~2023-05-02  0:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-28 18:27 [PATCH 0/3] Some struct ui / struct interps cleanup Simon Marchi
2023-04-28 18:27 ` [PATCH 1/3] gdb: move struct ui and related things to ui.{c,h} Simon Marchi
2023-04-28 18:27 ` [PATCH 2/3] gdb: store interps in an intrusive_list Simon Marchi
2023-04-28 18:27 ` [PATCH 3/3] gdb: remove ui_interp_info Simon Marchi
2023-05-01 15:25 ` [PATCH 0/3] Some struct ui / struct interps cleanup Tom Tromey
2023-05-02  0:49   ` Simon Marchi

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