Introduce interpreter factories
authorPedro Alves <palves@redhat.com>
Tue, 21 Jun 2016 00:11:45 +0000 (01:11 +0100)
committerPedro Alves <palves@redhat.com>
Tue, 21 Jun 2016 00:11:45 +0000 (01:11 +0100)
If every UI instance has its own set of interpreters, then the current
scheme of creating the interpreters at GDB initialization time no
longer works.  We need to create them whenever a new UI instance is
created.

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

gdb/ChangeLog:
2016-06-21  Pedro Alves  <palves@redhat.com>

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

gdb/ChangeLog
gdb/cli/cli-interp.c
gdb/interps.c
gdb/interps.h
gdb/main.c
gdb/mi/mi-interp.c
gdb/python/python.c
gdb/tui/tui-interp.c

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