}
 }
 
-/* Observer for the signal_received notification.  */
-
-static void
-cli_base_on_signal_received (enum gdb_signal siggnal)
+void
+cli_interp_base::on_signal_received (enum gdb_signal siggnal)
 {
-  SWITCH_THRU_ALL_UIS ()
-    {
-      cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
-      if (cli == nullptr)
-       continue;
-
-      print_signal_received_reason (cli->interp_ui_out (), siggnal);
-    }
+  print_signal_received_reason (this->interp_ui_out (), siggnal);
 }
 
 /* Observer for the signalled notification.  */
   /* Note these all work for both the CLI and TUI interpreters.  */
   gdb::observers::normal_stop.attach (cli_base_on_normal_stop,
                                      "cli-interp-base");
-  gdb::observers::signal_received.attach (cli_base_on_signal_received,
-                                         "cli-interp-base");
   gdb::observers::signal_exited.attach (cli_base_on_signal_exited,
                                        "cli-interp-base");
   gdb::observers::exited.attach (cli_base_on_exited, "cli-interp-base");
 
   void pre_command_loop () override;
   bool supports_command_editing () override;
 
+  void on_signal_received (gdb_signal sig) override;
+
 private:
   struct saved_output_files
   {
 
 #include "gdbsupport/buildargv.h"
 #include "extension.h"
 #include "disasm.h"
+#include "interps.h"
 
 /* Prototypes for local functions */
 
   return 0;
 }
 
+/* See infrun.h.  */
+
+void
+notify_signal_received (gdb_signal sig)
+{
+  interps_notify_signal_received (sig);
+  gdb::observers::signal_received.notify (sig);
+}
+
 /* Come here when the program has stopped with a signal.  */
 
 static void
        {
          /* The signal table tells us to print about this signal.  */
          target_terminal::ours_for_output ();
-         gdb::observers::signal_received.notify (ecs->event_thread->stop_signal ());
+         notify_signal_received (ecs->event_thread->stop_signal ());
          target_terminal::inferior ();
        }
 
   update_thread_list ();
 
   if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
-    gdb::observers::signal_received.notify (inferior_thread ()->stop_signal ());
+    notify_signal_received (inferior_thread ()->stop_signal ());
 
   /* As with the notification of thread events, we want to delay
      notifying the user that we've switched thread context until
 
                           frame_info_ptr frame,
                           struct symtab_and_line sal);
 
+/* Notify interpreters and observers that the current inferior has stopped with
+   signal SIG.  */
+extern void notify_signal_received (gdb_signal sig);
+
 /* Several print_*_reason helper functions to print why the inferior
    has stopped to the passed in UIOUT.  */
 
 
   return current_ui->current_interpreter;
 }
 
+/* Helper interps_notify_* functions.  Call METHOD on the top-level interpreter
+   of all UIs.  */
+
+template <typename ...Args>
+void
+interps_notify (void (interp::*method) (Args...), Args... args)
+{
+  SWITCH_THRU_ALL_UIS ()
+    {
+      interp *tli = top_level_interpreter ();
+      if (tli != nullptr)
+       (tli->*method) (args...);
+    }
+}
+
+/* See interps.h.  */
+
+void
+interps_notify_signal_received (gdb_signal sig)
+{
+  interps_notify (&interp::on_signal_received, sig);
+}
+
 /* This just adds the "interpreter-exec" command.  */
 void _initialize_interpreter ();
 void
 
   const char *name () const
   { return m_name; }
 
+  /* Notify the interpreter that the current inferior has stopped with signal
+     SIG.  */
+  virtual void on_signal_received (gdb_signal sig) {}
+
 private:
   /* The memory for this is static, it comes from literal strings (e.g. "cli").  */
   const char *m_name;
                                   const char *text,
                                   const char *word);
 
+/* Notify all interpreters that the current inferior has stopped with signal
+   SIG.  */
+extern void interps_notify_signal_received (gdb_signal sig);
+
 /* well-known interpreters */
 #define INTERP_CONSOLE         "console"
 #define INTERP_MI2             "mi2"
 
 static void mi_insert_notify_hooks (void);
 static void mi_remove_notify_hooks (void);
 
-static void mi_on_signal_received (enum gdb_signal siggnal);
 static void mi_on_signal_exited (enum gdb_signal siggnal);
 static void mi_on_exited (int exitstatus);
 static void mi_on_normal_stop (struct bpstat *bs, int print_frame);
    inferior has stopped to both the MI event channel and to the MI
    console.  If the MI interpreter is not active, print nothing.  */
 
-/* Observer for the signal_received notification.  */
-
-static void
-mi_on_signal_received (enum gdb_signal siggnal)
+void
+mi_interp::on_signal_received (enum gdb_signal siggnal)
 {
-  SWITCH_THRU_ALL_UIS ()
-    {
-      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 (this->mi_uiout, siggnal);
+  print_signal_received_reason (this->cli_uiout, siggnal);
 }
 
 /* Observer for the signal_exited notification.  */
   interp_factory_register (INTERP_MI4, mi_interp_factory);
   interp_factory_register (INTERP_MI, mi_interp_factory);
 
-  gdb::observers::signal_received.attach (mi_on_signal_received, "mi-interp");
   gdb::observers::signal_exited.attach (mi_on_signal_exited, "mi-interp");
   gdb::observers::exited.attach (mi_on_exited, "mi-interp");
   gdb::observers::no_history.attach (mi_on_no_history, "mi-interp");
 
                    bool debug_redirect) override;
   void pre_command_loop () override;
 
+  void on_signal_received (gdb_signal sig) override;
+
   /* MI's output channels */
   mi_console_file *out;
   mi_console_file *err;
 
       enum gdb_signal sig = ws.sig ();
 
       if (signal_print_state (sig))
-       gdb::observers::signal_received.notify (sig);
+       notify_signal_received (sig);
     }
   gdb::observers::normal_stop.notify (NULL, 1);
 }